diff --git a/.claude/settings.json b/.claude/settings.json index d116f06e..41f8f0fd 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -1,12 +1,12 @@ { "enabledMcpjsonServers": [ - "storkit" + "huskies" ], "permissions": { "allow": [ - "Bash(./server/target/debug/storkit:*)", - "Bash(./target/debug/storkit:*)", - "Bash(STORKIT_PORT=*)", + "Bash(./server/target/debug/huskies:*)", + "Bash(./target/debug/huskies:*)", + "Bash(HUSKIES_PORT=*)", "Bash(cargo build:*)", "Bash(cargo check:*)", "Bash(cargo clippy:*)", @@ -56,7 +56,7 @@ "WebFetch(domain:portkey.ai)", "WebFetch(domain:www.shuttle.dev)", "WebSearch", - "mcp__storkit__*", + "mcp__huskies__*", "Edit", "Write", "Bash(find *)", diff --git a/.dockerignore b/.dockerignore index ec606cf4..201beba3 100644 --- a/.dockerignore +++ b/.dockerignore @@ -2,9 +2,9 @@ **/target/ **/node_modules/ frontend/dist/ -.storkit/worktrees/ -.storkit/logs/ -.storkit/work/6_archived/ +.huskies/worktrees/ +.huskies/logs/ +.huskies/work/6_archived/ .git/ *.swp *.swo diff --git a/.gitignore b/.gitignore index 23191cdd..3cb44590 100644 --- a/.gitignore +++ b/.gitignore @@ -5,10 +5,10 @@ # Local environment (secrets) .env -# App specific (root-level; storkit subdirectory patterns live in .storkit/.gitignore) +# App specific (root-level; huskies subdirectory patterns live in .huskies/.gitignore) store.json -.storkit_port -.storkit/bot.toml.bak +.huskies_port +.huskies/bot.toml.bak # Rust stuff target diff --git a/.storkit/.gitignore b/.huskies/.gitignore similarity index 100% rename from .storkit/.gitignore rename to .huskies/.gitignore diff --git a/.storkit/README.md b/.huskies/README.md similarity index 97% rename from .storkit/README.md rename to .huskies/README.md index 894cab3c..125faa0d 100644 --- a/.storkit/README.md +++ b/.huskies/README.md @@ -17,14 +17,14 @@ When you start a new session with this project: - **Keep moving.** After each step is confirmed, immediately proceed to the next wizard step without waiting for the user to ask. 2. **Check for MCP Tools:** Read `.mcp.json` to discover the MCP server endpoint. Then list available tools by calling: ```bash - curl -s "$(jq -r '.mcpServers["storkit"].url' .mcp.json)" \ + curl -s "$(jq -r '.mcpServers["huskies"].url' .mcp.json)" \ -H 'Content-Type: application/json' \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' ``` This returns the full tool catalog (create stories, spawn agents, record tests, manage worktrees, etc.). Familiarize yourself with the available tools before proceeding. These tools allow you to directly manipulate the workflow and spawn subsidiary agents without manual file manipulation. -3. **Read Context:** Check `.storkit/specs/00_CONTEXT.md` for high-level project goals. -4. **Read Stack:** Check `.storkit/specs/tech/STACK.md` for technical constraints and patterns. -5. **Check Work Items:** Look at `.storkit/work/1_backlog/` and `.storkit/work/2_current/` to see what work is pending. +3. **Read Context:** Check `.huskies/specs/00_CONTEXT.md` for high-level project goals. +4. **Read Stack:** Check `.huskies/specs/tech/STACK.md` for technical constraints and patterns. +5. **Check Work Items:** Look at `.huskies/work/1_backlog/` and `.huskies/work/2_current/` to see what work is pending. --- @@ -238,7 +238,7 @@ If a user hands you this document and says "Apply this process to my project": Story Kit includes a chat bot that can be connected to one messaging platform at a time. The bot handles commands, LLM conversations, and pipeline notifications. -**Only one transport can be active at a time.** To configure the bot, copy the appropriate example file to `.storkit/bot.toml`: +**Only one transport can be active at a time.** To configure the bot, copy the appropriate example file to `.huskies/bot.toml`: | Transport | Example file | Webhook endpoint | |-----------|-------------|-----------------| @@ -248,7 +248,7 @@ Story Kit includes a chat bot that can be connected to one messaging platform at | Slack | `bot.toml.slack.example` | `/webhook/slack` | ```bash -cp .storkit/bot.toml.matrix.example .storkit/bot.toml +cp .huskies/bot.toml.matrix.example .huskies/bot.toml # Edit bot.toml with your credentials ``` diff --git a/.storkit/bot.toml.matrix.example b/.huskies/bot.toml.matrix.example similarity index 100% rename from .storkit/bot.toml.matrix.example rename to .huskies/bot.toml.matrix.example diff --git a/.storkit/bot.toml.slack.example b/.huskies/bot.toml.slack.example similarity index 100% rename from .storkit/bot.toml.slack.example rename to .huskies/bot.toml.slack.example diff --git a/.storkit/bot.toml.whatsapp-meta.example b/.huskies/bot.toml.whatsapp-meta.example similarity index 100% rename from .storkit/bot.toml.whatsapp-meta.example rename to .huskies/bot.toml.whatsapp-meta.example diff --git a/.storkit/bot.toml.whatsapp-twilio.example b/.huskies/bot.toml.whatsapp-twilio.example similarity index 100% rename from .storkit/bot.toml.whatsapp-twilio.example rename to .huskies/bot.toml.whatsapp-twilio.example diff --git a/.storkit/problems.md b/.huskies/problems.md similarity index 100% rename from .storkit/problems.md rename to .huskies/problems.md diff --git a/.storkit/project.toml b/.huskies/project.toml similarity index 98% rename from .storkit/project.toml rename to .huskies/project.toml index 7735cc84..507a4f00 100644 --- a/.storkit/project.toml +++ b/.huskies/project.toml @@ -74,7 +74,7 @@ Read CLAUDE.md first, then .story_kit/README.md to understand the dev process. ## Your Workflow ### 0. Read the Story -- Read the story file at `.storkit/work/3_qa/{{story_id}}.md` +- Read the story file at `.huskies/work/3_qa/{{story_id}}.md` - Extract every acceptance criterion (the `- [ ]` checkbox lines) - Keep this list in mind for Step 3 @@ -115,7 +115,7 @@ An AC fails if: - URL to visit in the browser - Things to check in the UI - curl commands to exercise relevant API endpoints -- Kill the test server when done: `pkill -f 'target.*storkit' || true` (NEVER use `pkill -f storkit` — it kills the vite dev server) +- Kill the test server when done: `pkill -f 'target.*huskies' || true` (NEVER use `pkill -f huskies` — it kills the vite dev server) ### 5. Produce Structured Report and Verdict Print your QA report to stdout. Then call `approve_qa` or `reject_qa` via the MCP tool based on the overall result. Use this format: @@ -184,7 +184,7 @@ Read CLAUDE.md first, then .story_kit/README.md to understand the dev process. ## Your Workflow ### 0. Read the Story -- Read the story file at `.storkit/work/3_qa/{{story_id}}.md` +- Read the story file at `.huskies/work/3_qa/{{story_id}}.md` - Extract every acceptance criterion (the `- [ ]` checkbox lines) - Keep this list in mind for Step 3 @@ -225,7 +225,7 @@ An AC fails if: - URL to visit in the browser - Things to check in the UI - curl commands to exercise relevant API endpoints -- Kill the test server when done: `pkill -f 'target.*storkit' || true` (NEVER use `pkill -f storkit` — it kills the vite dev server) +- Kill the test server when done: `pkill -f 'target.*huskies' || true` (NEVER use `pkill -f huskies` — it kills the vite dev server) ### 5. Produce Structured Report and Verdict Print your QA report to stdout. Then call `approve_qa` or `reject_qa` via the MCP tool based on the overall result. Use this format: diff --git a/.storkit/project.toml.example b/.huskies/project.toml.example similarity index 91% rename from .storkit/project.toml.example rename to .huskies/project.toml.example index 50f3bc5b..58a50be7 100644 --- a/.storkit/project.toml.example +++ b/.huskies/project.toml.example @@ -1,4 +1,4 @@ -# Example project.toml — copy to .storkit/project.toml and customise. +# Example project.toml — copy to .huskies/project.toml and customise. # This file is checked in; project.toml itself is gitignored (it may contain # instance-specific settings). @@ -37,7 +37,7 @@ max_turns = 50 max_budget_usd = 5.00 prompt = """ You are working in a git worktree on story {{story_id}}. -Read CLAUDE.md first, then .storkit/README.md to understand the dev process. +Read CLAUDE.md first, then .huskies/README.md to understand the dev process. Run: cd "{{worktree_path}}" && git difftool {{base_branch}}...HEAD Commit all your work before your process exits. """ diff --git a/.storkit/specs/00_CONTEXT.md b/.huskies/specs/00_CONTEXT.md similarity index 100% rename from .storkit/specs/00_CONTEXT.md rename to .huskies/specs/00_CONTEXT.md diff --git a/.storkit/specs/functional/SLACK_SETUP.md b/.huskies/specs/functional/SLACK_SETUP.md similarity index 75% rename from .storkit/specs/functional/SLACK_SETUP.md rename to .huskies/specs/functional/SLACK_SETUP.md index 062709ea..79491089 100644 --- a/.storkit/specs/functional/SLACK_SETUP.md +++ b/.huskies/specs/functional/SLACK_SETUP.md @@ -6,7 +6,7 @@ Slack integration is configured via `bot.toml` in the project's `.story_kit/` di ```toml transport = "slack" -display_name = "Storkit" +display_name = "Huskies" slack_bot_token = "xoxb-..." slack_signing_secret = "..." slack_channel_ids = ["C01ABCDEF"] @@ -29,11 +29,11 @@ Slash commands provide quick access to pipeline commands without mentioning the | Command | Description | |---------|-------------| -| `/storkit-status` | Show pipeline status and agent availability | -| `/storkit-cost` | Show token spend: 24h total, top stories, and breakdown | -| `/storkit-show` | Display the full text of a work item (e.g. `/storkit-show 42`) | -| `/storkit-git` | Show git status: branch, changes, ahead/behind | -| `/storkit-htop` | Show system and agent process dashboard | +| `/huskies-status` | Show pipeline status and agent availability | +| `/huskies-cost` | Show token spend: 24h total, top stories, and breakdown | +| `/huskies-show` | Display the full text of a work item (e.g. `/huskies-show 42`) | +| `/huskies-git` | Show git status: branch, changes, ahead/behind | +| `/huskies-htop` | Show system and agent process dashboard | All slash command responses are **ephemeral** — only the user who invoked the command sees the response. diff --git a/.storkit/specs/functional/UI_LAYOUT.md b/.huskies/specs/functional/UI_LAYOUT.md similarity index 100% rename from .storkit/specs/functional/UI_LAYOUT.md rename to .huskies/specs/functional/UI_LAYOUT.md diff --git a/.storkit/specs/functional/UI_UX.md b/.huskies/specs/functional/UI_UX.md similarity index 100% rename from .storkit/specs/functional/UI_UX.md rename to .huskies/specs/functional/UI_UX.md diff --git a/.storkit/specs/tech/STACK.md b/.huskies/specs/tech/STACK.md similarity index 96% rename from .storkit/specs/tech/STACK.md rename to .huskies/specs/tech/STACK.md index 5ec7edef..8ffea2ed 100644 --- a/.storkit/specs/tech/STACK.md +++ b/.huskies/specs/tech/STACK.md @@ -118,8 +118,8 @@ To support both Remote and Local models, the system implements a `ModelProvider` Multiple instances can run simultaneously in different worktrees. To avoid port conflicts: -- **Backend:** Set `STORKIT_PORT` to a unique port (default is 3001). Example: `STORKIT_PORT=3002 cargo run` -- **Frontend:** Run `npm run dev` from `frontend/`. It auto-selects the next unused port. It reads `STORKIT_PORT` to know which backend to talk to, so export it before running: `export STORKIT_PORT=3002 && cd frontend && npm run dev` +- **Backend:** Set `HUSKIES_PORT` to a unique port (default is 3001). Example: `HUSKIES_PORT=3002 cargo run` +- **Frontend:** Run `npm run dev` from `frontend/`. It auto-selects the next unused port. It reads `HUSKIES_PORT` to know which backend to talk to, so export it before running: `export HUSKIES_PORT=3002 && cd frontend && npm run dev` When running in a worktree, use a port that won't conflict with the main instance (3001). Ports 3002+ are good choices. diff --git a/.storkit/work/1_backlog/.gitkeep b/.huskies/work/1_backlog/.gitkeep similarity index 100% rename from .storkit/work/1_backlog/.gitkeep rename to .huskies/work/1_backlog/.gitkeep diff --git a/.storkit/work/1_backlog/260_refactor_upgrade_libsqlite3_sys.md b/.huskies/work/1_backlog/260_refactor_upgrade_libsqlite3_sys.md similarity index 100% rename from .storkit/work/1_backlog/260_refactor_upgrade_libsqlite3_sys.md rename to .huskies/work/1_backlog/260_refactor_upgrade_libsqlite3_sys.md diff --git a/.storkit/work/1_backlog/388_story_whatsapp_webhook_hmac_signature_verification.md b/.huskies/work/1_backlog/388_story_whatsapp_webhook_hmac_signature_verification.md similarity index 100% rename from .storkit/work/1_backlog/388_story_whatsapp_webhook_hmac_signature_verification.md rename to .huskies/work/1_backlog/388_story_whatsapp_webhook_hmac_signature_verification.md diff --git a/.storkit/work/1_backlog/408_spike_fly_io_machines_api_integration_for_multi_tenant_storkit_saas.md b/.huskies/work/1_backlog/408_spike_fly_io_machines_api_integration_for_multi_tenant_storkit_saas.md similarity index 86% rename from .storkit/work/1_backlog/408_spike_fly_io_machines_api_integration_for_multi_tenant_storkit_saas.md rename to .huskies/work/1_backlog/408_spike_fly_io_machines_api_integration_for_multi_tenant_storkit_saas.md index 06c95aac..07efa6c6 100644 --- a/.storkit/work/1_backlog/408_spike_fly_io_machines_api_integration_for_multi_tenant_storkit_saas.md +++ b/.huskies/work/1_backlog/408_spike_fly_io_machines_api_integration_for_multi_tenant_storkit_saas.md @@ -1,8 +1,8 @@ --- -name: "Fly.io Machines API integration for multi-tenant storkit SaaS" +name: "Fly.io Machines API integration for multi-tenant huskies SaaS" --- -# Spike 408: Fly.io Machines API integration for multi-tenant storkit SaaS +# Spike 408: Fly.io Machines API integration for multi-tenant huskies SaaS ## Question @@ -28,7 +28,7 @@ A thin Rust service using `reqwest` for the Machines API and `axum` for the reve - [ ] Test attaching a persistent volume to a machine and verify it persists across stop/start - [ ] Test secret injection — pass a dummy `credentials.json` as a Fly secret and verify it's readable inside the machine - [ ] Sketch the auth proxy: JWT validation → machine lookup → reverse proxy to machine's private IP; verify WebSocket proxying works -- [ ] Measure actual cold start time for a minimal storkit container image +- [ ] Measure actual cold start time for a minimal huskies container image - [ ] Document any API quirks, rate limits, or sharp edges discovered during testing ## Findings diff --git a/.storkit/work/1_backlog/411_story_multi_account_oauth_token_rotation_on_rate_limit.md b/.huskies/work/1_backlog/411_story_multi_account_oauth_token_rotation_on_rate_limit.md similarity index 87% rename from .storkit/work/1_backlog/411_story_multi_account_oauth_token_rotation_on_rate_limit.md rename to .huskies/work/1_backlog/411_story_multi_account_oauth_token_rotation_on_rate_limit.md index 43e39844..332225d1 100644 --- a/.storkit/work/1_backlog/411_story_multi_account_oauth_token_rotation_on_rate_limit.md +++ b/.huskies/work/1_backlog/411_story_multi_account_oauth_token_rotation_on_rate_limit.md @@ -6,13 +6,13 @@ name: "Multi-account OAuth token rotation on rate limit" ## User Story -As a storkit user with multiple Claude Max subscriptions, I want the system to automatically rotate to a different account when one gets rate limited, so that agents and chat don't stall out waiting for limits to reset. +As a huskies user with multiple Claude Max subscriptions, I want the system to automatically rotate to a different account when one gets rate limited, so that agents and chat don't stall out waiting for limits to reset. ## Acceptance Criteria - [ ] OAuth login flow stores credentials per-account (keyed by email), not overwriting previous accounts - [ ] GET /oauth/status returns all stored accounts and their status (active, rate-limited, expired) -- [ ] When the active account hits a rate limit, storkit automatically swaps to the next available account's refresh token, refreshes, and retries +- [ ] When the active account hits a rate limit, huskies automatically swaps to the next available account's refresh token, refreshes, and retries - [ ] The bot sends a notification in Matrix/WhatsApp when it swaps accounts - [ ] If all accounts are rate limited, the bot surfaces a clear message with the time until the earliest reset - [ ] A new /oauth/authorize login adds to the account pool rather than replacing the current credentials diff --git a/.storkit/work/1_backlog/412_story_recheck_bot_command_to_re_run_gates_without_restarting_agent.md b/.huskies/work/1_backlog/412_story_recheck_bot_command_to_re_run_gates_without_restarting_agent.md similarity index 100% rename from .storkit/work/1_backlog/412_story_recheck_bot_command_to_re_run_gates_without_restarting_agent.md rename to .huskies/work/1_backlog/412_story_recheck_bot_command_to_re_run_gates_without_restarting_agent.md diff --git a/.storkit/work/1_backlog/435_story_unblock_command_handles_all_stuck_states_not_just_blocked_flag.md b/.huskies/work/1_backlog/435_story_unblock_command_handles_all_stuck_states_not_just_blocked_flag.md similarity index 100% rename from .storkit/work/1_backlog/435_story_unblock_command_handles_all_stuck_states_not_just_blocked_flag.md rename to .huskies/work/1_backlog/435_story_unblock_command_handles_all_stuck_states_not_just_blocked_flag.md diff --git a/.storkit/work/1_backlog/436_refactor_unify_story_stuck_states_into_a_single_status_field.md b/.huskies/work/1_backlog/436_refactor_unify_story_stuck_states_into_a_single_status_field.md similarity index 100% rename from .storkit/work/1_backlog/436_refactor_unify_story_stuck_states_into_a_single_status_field.md rename to .huskies/work/1_backlog/436_refactor_unify_story_stuck_states_into_a_single_status_field.md diff --git a/.huskies/work/1_backlog/455_story_rename_project_from_storkit_to_huskies.md b/.huskies/work/1_backlog/455_story_rename_project_from_storkit_to_huskies.md new file mode 100644 index 00000000..13d9978c --- /dev/null +++ b/.huskies/work/1_backlog/455_story_rename_project_from_storkit_to_huskies.md @@ -0,0 +1,31 @@ +--- +name: "Rename project from \"huskies\" to \"huskies\"" +--- + +# Story 455: Rename project from "huskies" to "huskies" + +## User Story + +As a project maintainer, I want to rename the project from \"huskies\" to \"huskies\" so that the product has its new identity throughout the codebase, tooling, and documentation. The new domain is huskies.dev — update all references to huskies.dev accordingly (website, contact email hello@huskies.dev, etc). + +## Acceptance Criteria + +- [ ] Rust crate name in server/Cargo.toml changed from 'huskies' to 'huskies' +- [ ] Binary name changed to 'huskies' (Dockerfile CMD, release script binary names) +- [ ] Environment variables renamed: STORKIT_PORT → HUSKIES_PORT, STORKIT_HOST → HUSKIES_HOST +- [ ] Docker service name, container_name, image name, and volume names updated in docker-compose.yml +- [ ] Docker user/group renamed from 'huskies' to 'huskies' in Dockerfile (groupadd, useradd, home dir /home/huskies/.claude) +- [ ] MCP server registration renamed from 'huskies' to 'huskies' in scaffold-generated .mcp.json and in server/src/http/mcp/mod.rs serverInfo name +- [ ] All 35+ MCP tool permission patterns updated from mcp__huskies__* to mcp__huskies__* across code and permission configs +- [ ] The .huskies/ project directory marker renamed to .huskies/ throughout all Rust source (paths.rs, config.rs, scaffold.rs, watcher.rs, prompts.rs, and all agent/pipeline code) +- [ ] Release script updated: Gitea repo path dave/huskies → dave/huskies, changelog regex updated to match ^(huskies|huskies|story-kit): for backwards-compatible history parsing, binary artifact names updated +- [ ] Git commit prefix convention updated from 'huskies:' to 'huskies:' in huskies README and agent prompts +- [ ] Website updated: page title, headings, and contact email (hello@huskies.dev) if domain changes +- [ ] README.md updated: all CLI examples use 'huskies' binary name, all .huskies/ references become .huskies/ +- [ ] A migration path exists for existing installs: either huskies auto-detects and migrates .huskies/ → .huskies/, or a migration script (script/migrate) is provided +- [ ] All Claude Code .mcp.json files in existing worktrees are regenerated via scaffold or migration +- [ ] Gitea repository renamed from dave/huskies to dave/huskies (external action required, noted in story) + +## Out of Scope + +- TBD diff --git a/.storkit/work/1_backlog/467_story_mcp_tool_to_return_current_time_in_project_timezone.md b/.huskies/work/1_backlog/467_story_mcp_tool_to_return_current_time_in_project_timezone.md similarity index 100% rename from .storkit/work/1_backlog/467_story_mcp_tool_to_return_current_time_in_project_timezone.md rename to .huskies/work/1_backlog/467_story_mcp_tool_to_return_current_time_in_project_timezone.md diff --git a/.storkit/work/5_done/.gitkeep b/.huskies/work/5_done/.gitkeep similarity index 100% rename from .storkit/work/5_done/.gitkeep rename to .huskies/work/5_done/.gitkeep diff --git a/.storkit/work/5_done/462_bug_stage_transition_notifications_can_arrive_out_of_order_and_show_wrong_story_name.md b/.huskies/work/5_done/462_bug_stage_transition_notifications_can_arrive_out_of_order_and_show_wrong_story_name.md similarity index 100% rename from .storkit/work/5_done/462_bug_stage_transition_notifications_can_arrive_out_of_order_and_show_wrong_story_name.md rename to .huskies/work/5_done/462_bug_stage_transition_notifications_can_arrive_out_of_order_and_show_wrong_story_name.md diff --git a/.storkit/work/5_done/463_story_configurable_rate_limit_notification_suppression.md b/.huskies/work/5_done/463_story_configurable_rate_limit_notification_suppression.md similarity index 100% rename from .storkit/work/5_done/463_story_configurable_rate_limit_notification_suppression.md rename to .huskies/work/5_done/463_story_configurable_rate_limit_notification_suppression.md diff --git a/.storkit/work/5_done/464_bug_timer_rejects_backlog_stories_should_move_to_current_on_fire.md b/.huskies/work/5_done/464_bug_timer_rejects_backlog_stories_should_move_to_current_on_fire.md similarity index 100% rename from .storkit/work/5_done/464_bug_timer_rejects_backlog_stories_should_move_to_current_on_fire.md rename to .huskies/work/5_done/464_bug_timer_rejects_backlog_stories_should_move_to_current_on_fire.md diff --git a/.storkit/work/5_done/465_bug_timer_tick_loop_never_fires_due_entries.md b/.huskies/work/5_done/465_bug_timer_tick_loop_never_fires_due_entries.md similarity index 93% rename from .storkit/work/5_done/465_bug_timer_tick_loop_never_fires_due_entries.md rename to .huskies/work/5_done/465_bug_timer_tick_loop_never_fires_due_entries.md index b45a74cd..841e264c 100644 --- a/.storkit/work/5_done/465_bug_timer_tick_loop_never_fires_due_entries.md +++ b/.huskies/work/5_done/465_bug_timer_tick_loop_never_fires_due_entries.md @@ -7,7 +7,7 @@ agent: coder-opus ## Description -The timer tick loop (`spawn_timer_tick_loop`) is spawned by the Matrix bot runner, the Matrix bot is confirmed running (processing messages), but timers never fire. Past-due entries remain in `.storkit/timers.json` indefinitely — `take_due` never consumes them. +The timer tick loop (`spawn_timer_tick_loop`) is spawned by the Matrix bot runner, the Matrix bot is confirmed running (processing messages), but timers never fire. Past-due entries remain in `.huskies/timers.json` indefinitely — `take_due` never consumes them. The tick loop uses `tokio::spawn` which swallows panics silently. If `move_story_to_current` or `start_agent` panics on the first tick (when all past-due entries fire at once), the entire task dies with no log output. The PTY debug spam may also push any `[timer]` log entries out of the ring buffer. @@ -17,7 +17,7 @@ The bot command successfully adds entries to the in-memory store and persists th 1. Set a timer via bot command: `timer 463 HH:MM` (a time in the near future) 2. Wait past the scheduled time -3. Check `.storkit/timers.json` — entries are still present +3. Check `.huskies/timers.json` — entries are still present 4. Check server logs for `[timer]` — no entries found ## Actual Result diff --git a/.storkit/work/5_done/466_story_configurable_timezone_in_project_toml_for_timer_scheduling.md b/.huskies/work/5_done/466_story_configurable_timezone_in_project_toml_for_timer_scheduling.md similarity index 91% rename from .storkit/work/5_done/466_story_configurable_timezone_in_project_toml_for_timer_scheduling.md rename to .huskies/work/5_done/466_story_configurable_timezone_in_project_toml_for_timer_scheduling.md index b2f1c59f..c479738f 100644 --- a/.storkit/work/5_done/466_story_configurable_timezone_in_project_toml_for_timer_scheduling.md +++ b/.huskies/work/5_done/466_story_configurable_timezone_in_project_toml_for_timer_scheduling.md @@ -6,7 +6,7 @@ name: "Configurable timezone in project.toml for timer scheduling" ## User Story -As a user running storkit in a container where TZ defaults to UTC, I want to configure my project's timezone in project.toml so that timer HH:MM inputs are interpreted in my actual timezone. +As a user running huskies in a container where TZ defaults to UTC, I want to configure my project's timezone in project.toml so that timer HH:MM inputs are interpreted in my actual timezone. ## Acceptance Criteria diff --git a/.storkit/work/6_archived/01_story_project_selection.md b/.huskies/work/6_archived/01_story_project_selection.md similarity index 100% rename from .storkit/work/6_archived/01_story_project_selection.md rename to .huskies/work/6_archived/01_story_project_selection.md diff --git a/.storkit/work/6_archived/02_story_core_agent_tools.md b/.huskies/work/6_archived/02_story_core_agent_tools.md similarity index 100% rename from .storkit/work/6_archived/02_story_core_agent_tools.md rename to .huskies/work/6_archived/02_story_core_agent_tools.md diff --git a/.storkit/work/6_archived/03_story_llm_ollama.md b/.huskies/work/6_archived/03_story_llm_ollama.md similarity index 100% rename from .storkit/work/6_archived/03_story_llm_ollama.md rename to .huskies/work/6_archived/03_story_llm_ollama.md diff --git a/.storkit/work/6_archived/04_story_ollama_model_detection.md b/.huskies/work/6_archived/04_story_ollama_model_detection.md similarity index 100% rename from .storkit/work/6_archived/04_story_ollama_model_detection.md rename to .huskies/work/6_archived/04_story_ollama_model_detection.md diff --git a/.storkit/work/6_archived/05_story_persist_project_selection.md b/.huskies/work/6_archived/05_story_persist_project_selection.md similarity index 100% rename from .storkit/work/6_archived/05_story_persist_project_selection.md rename to .huskies/work/6_archived/05_story_persist_project_selection.md diff --git a/.storkit/work/6_archived/06_story_fix_ui_responsiveness.md b/.huskies/work/6_archived/06_story_fix_ui_responsiveness.md similarity index 100% rename from .storkit/work/6_archived/06_story_fix_ui_responsiveness.md rename to .huskies/work/6_archived/06_story_fix_ui_responsiveness.md diff --git a/.storkit/work/6_archived/07_story_ui_polish_sticky_header.md b/.huskies/work/6_archived/07_story_ui_polish_sticky_header.md similarity index 100% rename from .storkit/work/6_archived/07_story_ui_polish_sticky_header.md rename to .huskies/work/6_archived/07_story_ui_polish_sticky_header.md diff --git a/.storkit/work/6_archived/08_story_collapsible_tool_outputs.md b/.huskies/work/6_archived/08_story_collapsible_tool_outputs.md similarity index 100% rename from .storkit/work/6_archived/08_story_collapsible_tool_outputs.md rename to .huskies/work/6_archived/08_story_collapsible_tool_outputs.md diff --git a/.storkit/work/6_archived/09_story_remove_scroll_bars.md b/.huskies/work/6_archived/09_story_remove_scroll_bars.md similarity index 100% rename from .storkit/work/6_archived/09_story_remove_scroll_bars.md rename to .huskies/work/6_archived/09_story_remove_scroll_bars.md diff --git a/.storkit/work/6_archived/09_story_system_prompt_persona.md b/.huskies/work/6_archived/09_story_system_prompt_persona.md similarity index 100% rename from .storkit/work/6_archived/09_story_system_prompt_persona.md rename to .huskies/work/6_archived/09_story_system_prompt_persona.md diff --git a/.storkit/work/6_archived/100_story_test_coverage_http_context_rs_to_100.md b/.huskies/work/6_archived/100_story_test_coverage_http_context_rs_to_100.md similarity index 100% rename from .storkit/work/6_archived/100_story_test_coverage_http_context_rs_to_100.md rename to .huskies/work/6_archived/100_story_test_coverage_http_context_rs_to_100.md diff --git a/.storkit/work/6_archived/101_story_test_coverage_http_chat_rs_to_80.md b/.huskies/work/6_archived/101_story_test_coverage_http_chat_rs_to_80.md similarity index 100% rename from .storkit/work/6_archived/101_story_test_coverage_http_chat_rs_to_80.md rename to .huskies/work/6_archived/101_story_test_coverage_http_chat_rs_to_80.md diff --git a/.storkit/work/6_archived/102_story_test_coverage_http_model_rs_to_80.md b/.huskies/work/6_archived/102_story_test_coverage_http_model_rs_to_80.md similarity index 100% rename from .storkit/work/6_archived/102_story_test_coverage_http_model_rs_to_80.md rename to .huskies/work/6_archived/102_story_test_coverage_http_model_rs_to_80.md diff --git a/.storkit/work/6_archived/103_story_test_coverage_http_project_rs_to_80.md b/.huskies/work/6_archived/103_story_test_coverage_http_project_rs_to_80.md similarity index 100% rename from .storkit/work/6_archived/103_story_test_coverage_http_project_rs_to_80.md rename to .huskies/work/6_archived/103_story_test_coverage_http_project_rs_to_80.md diff --git a/.storkit/work/6_archived/104_story_test_coverage_io_search_rs_to_95.md b/.huskies/work/6_archived/104_story_test_coverage_io_search_rs_to_95.md similarity index 100% rename from .storkit/work/6_archived/104_story_test_coverage_io_search_rs_to_95.md rename to .huskies/work/6_archived/104_story_test_coverage_io_search_rs_to_95.md diff --git a/.storkit/work/6_archived/105_story_test_coverage_io_shell_rs_to_95.md b/.huskies/work/6_archived/105_story_test_coverage_io_shell_rs_to_95.md similarity index 100% rename from .storkit/work/6_archived/105_story_test_coverage_io_shell_rs_to_95.md rename to .huskies/work/6_archived/105_story_test_coverage_io_shell_rs_to_95.md diff --git a/.storkit/work/6_archived/106_story_test_coverage_http_settings_rs_to_80.md b/.huskies/work/6_archived/106_story_test_coverage_http_settings_rs_to_80.md similarity index 100% rename from .storkit/work/6_archived/106_story_test_coverage_http_settings_rs_to_80.md rename to .huskies/work/6_archived/106_story_test_coverage_http_settings_rs_to_80.md diff --git a/.storkit/work/6_archived/107_story_test_coverage_http_assets_rs_to_85.md b/.huskies/work/6_archived/107_story_test_coverage_http_assets_rs_to_85.md similarity index 100% rename from .storkit/work/6_archived/107_story_test_coverage_http_assets_rs_to_85.md rename to .huskies/work/6_archived/107_story_test_coverage_http_assets_rs_to_85.md diff --git a/.storkit/work/6_archived/108_story_test_coverage_http_agents_rs_to_70.md b/.huskies/work/6_archived/108_story_test_coverage_http_agents_rs_to_70.md similarity index 100% rename from .storkit/work/6_archived/108_story_test_coverage_http_agents_rs_to_70.md rename to .huskies/work/6_archived/108_story_test_coverage_http_agents_rs_to_70.md diff --git a/.storkit/work/6_archived/109_story_add_test_coverage_for_lozengeflycontext_selectionscreen_and_chatheader_components.md b/.huskies/work/6_archived/109_story_add_test_coverage_for_lozengeflycontext_selectionscreen_and_chatheader_components.md similarity index 100% rename from .storkit/work/6_archived/109_story_add_test_coverage_for_lozengeflycontext_selectionscreen_and_chatheader_components.md rename to .huskies/work/6_archived/109_story_add_test_coverage_for_lozengeflycontext_selectionscreen_and_chatheader_components.md diff --git a/.storkit/work/6_archived/10_story_persist_model_selection.md b/.huskies/work/6_archived/10_story_persist_model_selection.md similarity index 100% rename from .storkit/work/6_archived/10_story_persist_model_selection.md rename to .huskies/work/6_archived/10_story_persist_model_selection.md diff --git a/.storkit/work/6_archived/110_story_add_test_coverage_for_api_settings_ts.md b/.huskies/work/6_archived/110_story_add_test_coverage_for_api_settings_ts.md similarity index 100% rename from .storkit/work/6_archived/110_story_add_test_coverage_for_api_settings_ts.md rename to .huskies/work/6_archived/110_story_add_test_coverage_for_api_settings_ts.md diff --git a/.storkit/work/6_archived/111_story_add_test_coverage_for_api_agents_ts.md b/.huskies/work/6_archived/111_story_add_test_coverage_for_api_agents_ts.md similarity index 100% rename from .storkit/work/6_archived/111_story_add_test_coverage_for_api_agents_ts.md rename to .huskies/work/6_archived/111_story_add_test_coverage_for_api_agents_ts.md diff --git a/.storkit/work/6_archived/112_story_add_test_coverage_for_app_tsx.md b/.huskies/work/6_archived/112_story_add_test_coverage_for_app_tsx.md similarity index 100% rename from .storkit/work/6_archived/112_story_add_test_coverage_for_app_tsx.md rename to .huskies/work/6_archived/112_story_add_test_coverage_for_app_tsx.md diff --git a/.storkit/work/6_archived/113_story_add_test_coverage_for_usepathcompletion_hook.md b/.huskies/work/6_archived/113_story_add_test_coverage_for_usepathcompletion_hook.md similarity index 100% rename from .storkit/work/6_archived/113_story_add_test_coverage_for_usepathcompletion_hook.md rename to .huskies/work/6_archived/113_story_add_test_coverage_for_usepathcompletion_hook.md diff --git a/.storkit/work/6_archived/114_bug_web_ui_sse_socket_stops_updating_after_a_while.md b/.huskies/work/6_archived/114_bug_web_ui_sse_socket_stops_updating_after_a_while.md similarity index 100% rename from .storkit/work/6_archived/114_bug_web_ui_sse_socket_stops_updating_after_a_while.md rename to .huskies/work/6_archived/114_bug_web_ui_sse_socket_stops_updating_after_a_while.md diff --git a/.storkit/work/6_archived/115_story_hot_reload_project_toml_agent_config_without_server_restart.md b/.huskies/work/6_archived/115_story_hot_reload_project_toml_agent_config_without_server_restart.md similarity index 100% rename from .storkit/work/6_archived/115_story_hot_reload_project_toml_agent_config_without_server_restart.md rename to .huskies/work/6_archived/115_story_hot_reload_project_toml_agent_config_without_server_restart.md diff --git a/.storkit/work/6_archived/116_story_story_kit_init_command_scaffolds_a_new_project.md b/.huskies/work/6_archived/116_story_story_kit_init_command_scaffolds_a_new_project.md similarity index 100% rename from .storkit/work/6_archived/116_story_story_kit_init_command_scaffolds_a_new_project.md rename to .huskies/work/6_archived/116_story_story_kit_init_command_scaffolds_a_new_project.md diff --git a/.storkit/work/6_archived/117_story_show_startup_reconciliation_progress_in_ui.md b/.huskies/work/6_archived/117_story_show_startup_reconciliation_progress_in_ui.md similarity index 100% rename from .storkit/work/6_archived/117_story_show_startup_reconciliation_progress_in_ui.md rename to .huskies/work/6_archived/117_story_show_startup_reconciliation_progress_in_ui.md diff --git a/.storkit/work/6_archived/118_bug_agent_pool_retains_stale_running_state_after_completion_blocking_auto_assign.md b/.huskies/work/6_archived/118_bug_agent_pool_retains_stale_running_state_after_completion_blocking_auto_assign.md similarity index 100% rename from .storkit/work/6_archived/118_bug_agent_pool_retains_stale_running_state_after_completion_blocking_auto_assign.md rename to .huskies/work/6_archived/118_bug_agent_pool_retains_stale_running_state_after_completion_blocking_auto_assign.md diff --git a/.storkit/work/6_archived/119_story_mergemaster_should_resolve_merge_conflicts_instead_of_leaving_conflict_markers_on_master.md b/.huskies/work/6_archived/119_story_mergemaster_should_resolve_merge_conflicts_instead_of_leaving_conflict_markers_on_master.md similarity index 100% rename from .storkit/work/6_archived/119_story_mergemaster_should_resolve_merge_conflicts_instead_of_leaving_conflict_markers_on_master.md rename to .huskies/work/6_archived/119_story_mergemaster_should_resolve_merge_conflicts_instead_of_leaving_conflict_markers_on_master.md diff --git a/.storkit/work/6_archived/11_story_make_text_not_centred.md b/.huskies/work/6_archived/11_story_make_text_not_centred.md similarity index 100% rename from .storkit/work/6_archived/11_story_make_text_not_centred.md rename to .huskies/work/6_archived/11_story_make_text_not_centred.md diff --git a/.storkit/work/6_archived/120_story_test_coverage_llm_chat_rs.md b/.huskies/work/6_archived/120_story_test_coverage_llm_chat_rs.md similarity index 100% rename from .storkit/work/6_archived/120_story_test_coverage_llm_chat_rs.md rename to .huskies/work/6_archived/120_story_test_coverage_llm_chat_rs.md diff --git a/.storkit/work/6_archived/121_story_test_coverage_io_watcher_rs.md b/.huskies/work/6_archived/121_story_test_coverage_io_watcher_rs.md similarity index 100% rename from .storkit/work/6_archived/121_story_test_coverage_io_watcher_rs.md rename to .huskies/work/6_archived/121_story_test_coverage_io_watcher_rs.md diff --git a/.storkit/work/6_archived/122_story_test_coverage_http_ws_rs.md b/.huskies/work/6_archived/122_story_test_coverage_http_ws_rs.md similarity index 100% rename from .storkit/work/6_archived/122_story_test_coverage_http_ws_rs.md rename to .huskies/work/6_archived/122_story_test_coverage_http_ws_rs.md diff --git a/.storkit/work/6_archived/123_story_test_coverage_llm_providers_anthropic_rs.md b/.huskies/work/6_archived/123_story_test_coverage_llm_providers_anthropic_rs.md similarity index 100% rename from .storkit/work/6_archived/123_story_test_coverage_llm_providers_anthropic_rs.md rename to .huskies/work/6_archived/123_story_test_coverage_llm_providers_anthropic_rs.md diff --git a/.storkit/work/6_archived/124_story_test_coverage_llm_providers_claude_code_rs.md b/.huskies/work/6_archived/124_story_test_coverage_llm_providers_claude_code_rs.md similarity index 100% rename from .storkit/work/6_archived/124_story_test_coverage_llm_providers_claude_code_rs.md rename to .huskies/work/6_archived/124_story_test_coverage_llm_providers_claude_code_rs.md diff --git a/.storkit/work/6_archived/125_story_test_coverage_http_io_rs.md b/.huskies/work/6_archived/125_story_test_coverage_http_io_rs.md similarity index 100% rename from .storkit/work/6_archived/125_story_test_coverage_http_io_rs.md rename to .huskies/work/6_archived/125_story_test_coverage_http_io_rs.md diff --git a/.storkit/work/6_archived/126_story_test_coverage_http_anthropic_rs.md b/.huskies/work/6_archived/126_story_test_coverage_http_anthropic_rs.md similarity index 100% rename from .storkit/work/6_archived/126_story_test_coverage_http_anthropic_rs.md rename to .huskies/work/6_archived/126_story_test_coverage_http_anthropic_rs.md diff --git a/.storkit/work/6_archived/127_story_test_coverage_http_mod_rs.md b/.huskies/work/6_archived/127_story_test_coverage_http_mod_rs.md similarity index 100% rename from .storkit/work/6_archived/127_story_test_coverage_http_mod_rs.md rename to .huskies/work/6_archived/127_story_test_coverage_http_mod_rs.md diff --git a/.storkit/work/6_archived/128_story_test_coverage_worktree_rs.md b/.huskies/work/6_archived/128_story_test_coverage_worktree_rs.md similarity index 100% rename from .storkit/work/6_archived/128_story_test_coverage_worktree_rs.md rename to .huskies/work/6_archived/128_story_test_coverage_worktree_rs.md diff --git a/.storkit/work/6_archived/129_story_test_coverage_http_mcp_rs.md b/.huskies/work/6_archived/129_story_test_coverage_http_mcp_rs.md similarity index 100% rename from .storkit/work/6_archived/129_story_test_coverage_http_mcp_rs.md rename to .huskies/work/6_archived/129_story_test_coverage_http_mcp_rs.md diff --git a/.storkit/work/6_archived/12_story_be_able_to_use_claude.md b/.huskies/work/6_archived/12_story_be_able_to_use_claude.md similarity index 100% rename from .storkit/work/6_archived/12_story_be_able_to_use_claude.md rename to .huskies/work/6_archived/12_story_be_able_to_use_claude.md diff --git a/.storkit/work/6_archived/130_bug_permission_approval_returns_wrong_format_tools_fail_after_user_approves.md b/.huskies/work/6_archived/130_bug_permission_approval_returns_wrong_format_tools_fail_after_user_approves.md similarity index 97% rename from .storkit/work/6_archived/130_bug_permission_approval_returns_wrong_format_tools_fail_after_user_approves.md rename to .huskies/work/6_archived/130_bug_permission_approval_returns_wrong_format_tools_fail_after_user_approves.md index 0338004d..0e8410c0 100644 --- a/.storkit/work/6_archived/130_bug_permission_approval_returns_wrong_format_tools_fail_after_user_approves.md +++ b/.huskies/work/6_archived/130_bug_permission_approval_returns_wrong_format_tools_fail_after_user_approves.md @@ -10,7 +10,7 @@ The `prompt_permission` MCP tool returns plain text ("Permission granted for '.. ## How to Reproduce -1. Start the storkit server and open the web UI +1. Start the huskies server and open the web UI 2. Chat with the claude-code-pty model 3. Ask it to do something that requires a tool NOT in `.claude/settings.json` allow list (e.g. `wc -l /etc/hosts`, or WebFetch to a non-allowed domain) 4. The permission dialog appears — click Approve diff --git a/.storkit/work/6_archived/131_bug_get_agent_output_stream_always_times_out_for_running_agents.md b/.huskies/work/6_archived/131_bug_get_agent_output_stream_always_times_out_for_running_agents.md similarity index 100% rename from .storkit/work/6_archived/131_bug_get_agent_output_stream_always_times_out_for_running_agents.md rename to .huskies/work/6_archived/131_bug_get_agent_output_stream_always_times_out_for_running_agents.md diff --git a/.storkit/work/6_archived/132_story_fix_toctou_race_in_agent_check_and_insert.md b/.huskies/work/6_archived/132_story_fix_toctou_race_in_agent_check_and_insert.md similarity index 100% rename from .storkit/work/6_archived/132_story_fix_toctou_race_in_agent_check_and_insert.md rename to .huskies/work/6_archived/132_story_fix_toctou_race_in_agent_check_and_insert.md diff --git a/.storkit/work/6_archived/133_story_clean_up_agent_state_on_story_archive_and_add_ttl_for_completed_entries.md b/.huskies/work/6_archived/133_story_clean_up_agent_state_on_story_archive_and_add_ttl_for_completed_entries.md similarity index 100% rename from .storkit/work/6_archived/133_story_clean_up_agent_state_on_story_archive_and_add_ttl_for_completed_entries.md rename to .huskies/work/6_archived/133_story_clean_up_agent_state_on_story_archive_and_add_ttl_for_completed_entries.md diff --git a/.storkit/work/6_archived/134_story_add_process_health_monitoring_and_timeout_to_agent_pty_sessions.md b/.huskies/work/6_archived/134_story_add_process_health_monitoring_and_timeout_to_agent_pty_sessions.md similarity index 100% rename from .storkit/work/6_archived/134_story_add_process_health_monitoring_and_timeout_to_agent_pty_sessions.md rename to .huskies/work/6_archived/134_story_add_process_health_monitoring_and_timeout_to_agent_pty_sessions.md diff --git a/.storkit/work/6_archived/135_story_update_mergemaster_prompt_to_allow_conflict_resolution_and_code_fixes.md b/.huskies/work/6_archived/135_story_update_mergemaster_prompt_to_allow_conflict_resolution_and_code_fixes.md similarity index 100% rename from .storkit/work/6_archived/135_story_update_mergemaster_prompt_to_allow_conflict_resolution_and_code_fixes.md rename to .huskies/work/6_archived/135_story_update_mergemaster_prompt_to_allow_conflict_resolution_and_code_fixes.md diff --git a/.storkit/work/6_archived/136_bug_broadcast_channel_silently_drops_events_on_subscriber_lag.md b/.huskies/work/6_archived/136_bug_broadcast_channel_silently_drops_events_on_subscriber_lag.md similarity index 100% rename from .storkit/work/6_archived/136_bug_broadcast_channel_silently_drops_events_on_subscriber_lag.md rename to .huskies/work/6_archived/136_bug_broadcast_channel_silently_drops_events_on_subscriber_lag.md diff --git a/.storkit/work/6_archived/137_bug_lozengeflycontext_animation_queue_race_condition_on_rapid_updates.md b/.huskies/work/6_archived/137_bug_lozengeflycontext_animation_queue_race_condition_on_rapid_updates.md similarity index 100% rename from .storkit/work/6_archived/137_bug_lozengeflycontext_animation_queue_race_condition_on_rapid_updates.md rename to .huskies/work/6_archived/137_bug_lozengeflycontext_animation_queue_race_condition_on_rapid_updates.md diff --git a/.storkit/work/6_archived/138_bug_no_heartbeat_to_detect_stale_websocket_connections.md b/.huskies/work/6_archived/138_bug_no_heartbeat_to_detect_stale_websocket_connections.md similarity index 100% rename from .storkit/work/6_archived/138_bug_no_heartbeat_to_detect_stale_websocket_connections.md rename to .huskies/work/6_archived/138_bug_no_heartbeat_to_detect_stale_websocket_connections.md diff --git a/.storkit/work/6_archived/139_story_retry_limit_for_mergemaster_and_pipeline_restarts.md b/.huskies/work/6_archived/139_story_retry_limit_for_mergemaster_and_pipeline_restarts.md similarity index 92% rename from .storkit/work/6_archived/139_story_retry_limit_for_mergemaster_and_pipeline_restarts.md rename to .huskies/work/6_archived/139_story_retry_limit_for_mergemaster_and_pipeline_restarts.md index 99a07a4a..b31b2d38 100644 --- a/.storkit/work/6_archived/139_story_retry_limit_for_mergemaster_and_pipeline_restarts.md +++ b/.huskies/work/6_archived/139_story_retry_limit_for_mergemaster_and_pipeline_restarts.md @@ -6,7 +6,7 @@ name: "Retry limit for mergemaster and pipeline restarts" ## User Story -As a developer using storkit, I want pipeline auto-restarts to have a configurable retry limit so that failing agents don't loop infinitely consuming CPU and API credits. +As a developer using huskies, I want pipeline auto-restarts to have a configurable retry limit so that failing agents don't loop infinitely consuming CPU and API credits. ## Acceptance Criteria diff --git a/.storkit/work/6_archived/13_story_stop_button.md b/.huskies/work/6_archived/13_story_stop_button.md similarity index 100% rename from .storkit/work/6_archived/13_story_stop_button.md rename to .huskies/work/6_archived/13_story_stop_button.md diff --git a/.storkit/work/6_archived/140_bug_activity_status_indicator_never_visible_due_to_display_condition.md b/.huskies/work/6_archived/140_bug_activity_status_indicator_never_visible_due_to_display_condition.md similarity index 100% rename from .storkit/work/6_archived/140_bug_activity_status_indicator_never_visible_due_to_display_condition.md rename to .huskies/work/6_archived/140_bug_activity_status_indicator_never_visible_due_to_display_condition.md diff --git a/.storkit/work/6_archived/141_story_improve_server_logging_with_timestamps_and_error_visibility.md b/.huskies/work/6_archived/141_story_improve_server_logging_with_timestamps_and_error_visibility.md similarity index 100% rename from .storkit/work/6_archived/141_story_improve_server_logging_with_timestamps_and_error_visibility.md rename to .huskies/work/6_archived/141_story_improve_server_logging_with_timestamps_and_error_visibility.md diff --git a/.storkit/work/6_archived/142_bug_quality_gates_run_after_fast_forward_to_master_instead_of_before.md b/.huskies/work/6_archived/142_bug_quality_gates_run_after_fast_forward_to_master_instead_of_before.md similarity index 100% rename from .storkit/work/6_archived/142_bug_quality_gates_run_after_fast_forward_to_master_instead_of_before.md rename to .huskies/work/6_archived/142_bug_quality_gates_run_after_fast_forward_to_master_instead_of_before.md diff --git a/.storkit/work/6_archived/143_story_remove_0_running_count_from_agents_panel_header.md b/.huskies/work/6_archived/143_story_remove_0_running_count_from_agents_panel_header.md similarity index 100% rename from .storkit/work/6_archived/143_story_remove_0_running_count_from_agents_panel_header.md rename to .huskies/work/6_archived/143_story_remove_0_running_count_from_agents_panel_header.md diff --git a/.storkit/work/6_archived/144_story_add_build_timestamp_and_persist_chat_history_across_rebuilds.md b/.huskies/work/6_archived/144_story_add_build_timestamp_and_persist_chat_history_across_rebuilds.md similarity index 100% rename from .storkit/work/6_archived/144_story_add_build_timestamp_and_persist_chat_history_across_rebuilds.md rename to .huskies/work/6_archived/144_story_add_build_timestamp_and_persist_chat_history_across_rebuilds.md diff --git a/.storkit/work/6_archived/145_story_persist_chat_history_to_localstorage_across_rebuilds.md b/.huskies/work/6_archived/145_story_persist_chat_history_to_localstorage_across_rebuilds.md similarity index 100% rename from .storkit/work/6_archived/145_story_persist_chat_history_to_localstorage_across_rebuilds.md rename to .huskies/work/6_archived/145_story_persist_chat_history_to_localstorage_across_rebuilds.md diff --git a/.storkit/work/6_archived/146_bug_permission_approval_still_returns_wrong_format_needs_updatedinput_not_behavior_allow.md b/.huskies/work/6_archived/146_bug_permission_approval_still_returns_wrong_format_needs_updatedinput_not_behavior_allow.md similarity index 100% rename from .storkit/work/6_archived/146_bug_permission_approval_still_returns_wrong_format_needs_updatedinput_not_behavior_allow.md rename to .huskies/work/6_archived/146_bug_permission_approval_still_returns_wrong_format_needs_updatedinput_not_behavior_allow.md diff --git a/.storkit/work/6_archived/147_bug_activity_indicator_still_only_shows_thinking_despite_bug_140_fix.md b/.huskies/work/6_archived/147_bug_activity_indicator_still_only_shows_thinking_despite_bug_140_fix.md similarity index 100% rename from .storkit/work/6_archived/147_bug_activity_indicator_still_only_shows_thinking_despite_bug_140_fix.md rename to .huskies/work/6_archived/147_bug_activity_indicator_still_only_shows_thinking_despite_bug_140_fix.md diff --git a/.storkit/work/6_archived/148_story_interactive_onboarding_guides_user_through_project_setup_after_init.md b/.huskies/work/6_archived/148_story_interactive_onboarding_guides_user_through_project_setup_after_init.md similarity index 100% rename from .storkit/work/6_archived/148_story_interactive_onboarding_guides_user_through_project_setup_after_init.md rename to .huskies/work/6_archived/148_story_interactive_onboarding_guides_user_through_project_setup_after_init.md diff --git a/.storkit/work/6_archived/149_bug_web_ui_does_not_update_when_agents_are_started_or_stopped.md b/.huskies/work/6_archived/149_bug_web_ui_does_not_update_when_agents_are_started_or_stopped.md similarity index 100% rename from .storkit/work/6_archived/149_bug_web_ui_does_not_update_when_agents_are_started_or_stopped.md rename to .huskies/work/6_archived/149_bug_web_ui_does_not_update_when_agents_are_started_or_stopped.md diff --git a/.storkit/work/6_archived/14_story_put_cursor_in_chat_box_on_startup.md b/.huskies/work/6_archived/14_story_put_cursor_in_chat_box_on_startup.md similarity index 100% rename from .storkit/work/6_archived/14_story_put_cursor_in_chat_box_on_startup.md rename to .huskies/work/6_archived/14_story_put_cursor_in_chat_box_on_startup.md diff --git a/.storkit/work/6_archived/150_bug_qa_2_agent_never_auto_assigned_because_pipeline_stage_only_matches_exact_qa.md b/.huskies/work/6_archived/150_bug_qa_2_agent_never_auto_assigned_because_pipeline_stage_only_matches_exact_qa.md similarity index 100% rename from .storkit/work/6_archived/150_bug_qa_2_agent_never_auto_assigned_because_pipeline_stage_only_matches_exact_qa.md rename to .huskies/work/6_archived/150_bug_qa_2_agent_never_auto_assigned_because_pipeline_stage_only_matches_exact_qa.md diff --git a/.storkit/work/6_archived/151_story_split_archived_into_done_and_archived_with_time_based_promotion.md b/.huskies/work/6_archived/151_story_split_archived_into_done_and_archived_with_time_based_promotion.md similarity index 93% rename from .storkit/work/6_archived/151_story_split_archived_into_done_and_archived_with_time_based_promotion.md rename to .huskies/work/6_archived/151_story_split_archived_into_done_and_archived_with_time_based_promotion.md index 89f90fc7..440e473b 100644 --- a/.storkit/work/6_archived/151_story_split_archived_into_done_and_archived_with_time_based_promotion.md +++ b/.huskies/work/6_archived/151_story_split_archived_into_done_and_archived_with_time_based_promotion.md @@ -23,7 +23,7 @@ The watcher should periodically check `5_done/` and move items older than 4 hour - All MCP tools and pipeline logic that reference `5_archived` need updating to use `5_done` - Frontend pipeline display if it shows archived/done items - `.story_kit/README.md`: update pipeline stage documentation -- Story 116's init scaffolding: `storkit init` must create `5_done/` and `6_archived/` directories +- Story 116's init scaffolding: `huskies init` must create `5_done/` and `6_archived/` directories - Any templates or scaffold code that creates the `.story_kit/work/` directory structure ## Acceptance Criteria @@ -35,7 +35,7 @@ The watcher should periodically check `5_done/` and move items older than 4 hour - [ ] Existing items in old `5_archived/` are migrated to `6_archived/` - [ ] Frontend pipeline display updated if applicable - [ ] `.story_kit/README.md` updated to reflect the new pipeline stages -- [ ] `storkit init` scaffolding creates `5_done/` and `6_archived/` (coordinate with story 116) +- [ ] `huskies init` scaffolding creates `5_done/` and `6_archived/` (coordinate with story 116) ## Out of Scope diff --git a/.storkit/work/6_archived/152_bug_ollama_not_running_kills_the_entire_web_ui.md b/.huskies/work/6_archived/152_bug_ollama_not_running_kills_the_entire_web_ui.md similarity index 100% rename from .storkit/work/6_archived/152_bug_ollama_not_running_kills_the_entire_web_ui.md rename to .huskies/work/6_archived/152_bug_ollama_not_running_kills_the_entire_web_ui.md diff --git a/.storkit/work/6_archived/153_bug_auto_assign_broken_after_stage_field_was_added_to_agent_config.md b/.huskies/work/6_archived/153_bug_auto_assign_broken_after_stage_field_was_added_to_agent_config.md similarity index 100% rename from .storkit/work/6_archived/153_bug_auto_assign_broken_after_stage_field_was_added_to_agent_config.md rename to .huskies/work/6_archived/153_bug_auto_assign_broken_after_stage_field_was_added_to_agent_config.md diff --git a/.storkit/work/6_archived/154_bug_mergemaster_quality_gates_fail_because_merge_worktree_has_no_frontend_deps.md b/.huskies/work/6_archived/154_bug_mergemaster_quality_gates_fail_because_merge_worktree_has_no_frontend_deps.md similarity index 100% rename from .storkit/work/6_archived/154_bug_mergemaster_quality_gates_fail_because_merge_worktree_has_no_frontend_deps.md rename to .huskies/work/6_archived/154_bug_mergemaster_quality_gates_fail_because_merge_worktree_has_no_frontend_deps.md diff --git a/.storkit/work/6_archived/155_story_queue_messages_while_agent_is_busy.md b/.huskies/work/6_archived/155_story_queue_messages_while_agent_is_busy.md similarity index 100% rename from .storkit/work/6_archived/155_story_queue_messages_while_agent_is_busy.md rename to .huskies/work/6_archived/155_story_queue_messages_while_agent_is_busy.md diff --git a/.storkit/work/6_archived/156_bug_onboarding_welcome_screen_triggers_on_already_configured_projects.md b/.huskies/work/6_archived/156_bug_onboarding_welcome_screen_triggers_on_already_configured_projects.md similarity index 88% rename from .storkit/work/6_archived/156_bug_onboarding_welcome_screen_triggers_on_already_configured_projects.md rename to .huskies/work/6_archived/156_bug_onboarding_welcome_screen_triggers_on_already_configured_projects.md index d105b6c8..b6897bc3 100644 --- a/.storkit/work/6_archived/156_bug_onboarding_welcome_screen_triggers_on_already_configured_projects.md +++ b/.huskies/work/6_archived/156_bug_onboarding_welcome_screen_triggers_on_already_configured_projects.md @@ -17,21 +17,21 @@ const TEMPLATE_MARKER_CONTEXT: &str = "Agentic AI Code Assistant"; const TEMPLATE_MARKER_STACK: &str = "Agentic Code Assistant"; ``` -These markers are phrases that appear in the scaffold templates (`server/src/io/fs.rs` lines 233 and 269). The detection logic (`is_template_or_missing` at line 59) checks if the file *contains* the marker string. But these phrases are generic enough that real project content can contain them too — especially when the project being managed IS an agentic code assistant (i.e. storkit managing itself). +These markers are phrases that appear in the scaffold templates (`server/src/io/fs.rs` lines 233 and 269). The detection logic (`is_template_or_missing` at line 59) checks if the file *contains* the marker string. But these phrases are generic enough that real project content can contain them too — especially when the project being managed IS an agentic code assistant (i.e. huskies managing itself). ## The Fix Replace the content-based marker detection with a dedicated sentinel comment that only exists in untouched scaffold templates. The sentinel should be something that would never appear in real content, like an HTML comment: ``` - + ``` Changes needed: -1. **`server/src/io/onboarding.rs`**: Replace `TEMPLATE_MARKER_CONTEXT` and `TEMPLATE_MARKER_STACK` with a single `TEMPLATE_SENTINEL` constant set to `""`. Update `check_onboarding_status` to use it for both context and stack checks. +1. **`server/src/io/onboarding.rs`**: Replace `TEMPLATE_MARKER_CONTEXT` and `TEMPLATE_MARKER_STACK` with a single `TEMPLATE_SENTINEL` constant set to `""`. Update `check_onboarding_status` to use it for both context and stack checks. -2. **`server/src/io/fs.rs`**: Add `` as the first line of both `STORY_KIT_CONTEXT` and `STORY_KIT_STACK` template constants (lines 233 and 269). +2. **`server/src/io/fs.rs`**: Add `` as the first line of both `STORY_KIT_CONTEXT` and `STORY_KIT_STACK` template constants (lines 233 and 269). 3. **`server/src/io/onboarding.rs` tests**: Update the test `needs_onboarding_true_when_specs_contain_scaffold_markers` to use the sentinel instead of the old marker phrases. Also add a test confirming that content containing "Agentic AI Code Assistant" WITHOUT the sentinel does NOT trigger onboarding. @@ -42,7 +42,7 @@ Changes needed: ## Acceptance Criteria -- [ ] Scaffold templates contain the sentinel `` as first line +- [ ] Scaffold templates contain the sentinel `` as first line - [ ] `needs_onboarding()` returns false for projects whose specs contain "Agentic AI Code Assistant" but NOT the sentinel - [ ] `needs_onboarding()` returns true for untouched scaffold content (which contains the sentinel) - [ ] Existing tests updated and passing diff --git a/.storkit/work/6_archived/157_story_make_start_agent_non_blocking_by_deferring_worktree_creation.md b/.huskies/work/6_archived/157_story_make_start_agent_non_blocking_by_deferring_worktree_creation.md similarity index 100% rename from .storkit/work/6_archived/157_story_make_start_agent_non_blocking_by_deferring_worktree_creation.md rename to .huskies/work/6_archived/157_story_make_start_agent_non_blocking_by_deferring_worktree_creation.md diff --git a/.storkit/work/6_archived/158_bug_pty_debug_log_panics_on_multi_byte_utf_8_characters.md b/.huskies/work/6_archived/158_bug_pty_debug_log_panics_on_multi_byte_utf_8_characters.md similarity index 100% rename from .storkit/work/6_archived/158_bug_pty_debug_log_panics_on_multi_byte_utf_8_characters.md rename to .huskies/work/6_archived/158_bug_pty_debug_log_panics_on_multi_byte_utf_8_characters.md diff --git a/.storkit/work/6_archived/159_bug_server_restart_leaves_orphaned_claude_code_pty_processes_running.md b/.huskies/work/6_archived/159_bug_server_restart_leaves_orphaned_claude_code_pty_processes_running.md similarity index 100% rename from .storkit/work/6_archived/159_bug_server_restart_leaves_orphaned_claude_code_pty_processes_running.md rename to .huskies/work/6_archived/159_bug_server_restart_leaves_orphaned_claude_code_pty_processes_running.md diff --git a/.storkit/work/6_archived/15_story_new_session_cancellation.md b/.huskies/work/6_archived/15_story_new_session_cancellation.md similarity index 100% rename from .storkit/work/6_archived/15_story_new_session_cancellation.md rename to .huskies/work/6_archived/15_story_new_session_cancellation.md diff --git a/.storkit/work/6_archived/160_story_constrain_thinking_trace_height_in_agent_stream_ui.md b/.huskies/work/6_archived/160_story_constrain_thinking_trace_height_in_agent_stream_ui.md similarity index 100% rename from .storkit/work/6_archived/160_story_constrain_thinking_trace_height_in_agent_stream_ui.md rename to .huskies/work/6_archived/160_story_constrain_thinking_trace_height_in_agent_stream_ui.md diff --git a/.storkit/work/6_archived/161_bug_auto_assign_only_triggers_on_agent_completion_not_on_failure_or_periodically.md b/.huskies/work/6_archived/161_bug_auto_assign_only_triggers_on_agent_completion_not_on_failure_or_periodically.md similarity index 100% rename from .storkit/work/6_archived/161_bug_auto_assign_only_triggers_on_agent_completion_not_on_failure_or_periodically.md rename to .huskies/work/6_archived/161_bug_auto_assign_only_triggers_on_agent_completion_not_on_failure_or_periodically.md diff --git a/.storkit/work/6_archived/162_story_colored_server_terminal_log_output.md b/.huskies/work/6_archived/162_story_colored_server_terminal_log_output.md similarity index 100% rename from .storkit/work/6_archived/162_story_colored_server_terminal_log_output.md rename to .huskies/work/6_archived/162_story_colored_server_terminal_log_output.md diff --git a/.storkit/work/6_archived/163_story_remove_bubble_styling_from_streaming_chat_messages.md b/.huskies/work/6_archived/163_story_remove_bubble_styling_from_streaming_chat_messages.md similarity index 100% rename from .storkit/work/6_archived/163_story_remove_bubble_styling_from_streaming_chat_messages.md rename to .huskies/work/6_archived/163_story_remove_bubble_styling_from_streaming_chat_messages.md diff --git a/.storkit/work/6_archived/164_bug_dev_process_readme_documents_wrong_pipeline_stages.md b/.huskies/work/6_archived/164_bug_dev_process_readme_documents_wrong_pipeline_stages.md similarity index 100% rename from .storkit/work/6_archived/164_bug_dev_process_readme_documents_wrong_pipeline_stages.md rename to .huskies/work/6_archived/164_bug_dev_process_readme_documents_wrong_pipeline_stages.md diff --git a/.storkit/work/6_archived/165_bug_pipeline_log_message_says_archived_instead_of_done.md b/.huskies/work/6_archived/165_bug_pipeline_log_message_says_archived_instead_of_done.md similarity index 100% rename from .storkit/work/6_archived/165_bug_pipeline_log_message_says_archived_instead_of_done.md rename to .huskies/work/6_archived/165_bug_pipeline_log_message_says_archived_instead_of_done.md diff --git a/.storkit/work/6_archived/166_story_add_done_column_to_pipeline_board.md b/.huskies/work/6_archived/166_story_add_done_column_to_pipeline_board.md similarity index 100% rename from .storkit/work/6_archived/166_story_add_done_column_to_pipeline_board.md rename to .huskies/work/6_archived/166_story_add_done_column_to_pipeline_board.md diff --git a/.storkit/work/6_archived/167_bug_thinking_trace_height_constraint_not_working_in_web_ui.md b/.huskies/work/6_archived/167_bug_thinking_trace_height_constraint_not_working_in_web_ui.md similarity index 100% rename from .storkit/work/6_archived/167_bug_thinking_trace_height_constraint_not_working_in_web_ui.md rename to .huskies/work/6_archived/167_bug_thinking_trace_height_constraint_not_working_in_web_ui.md diff --git a/.storkit/work/6_archived/168_bug_agent_message_queue_limited_to_one_line.md b/.huskies/work/6_archived/168_bug_agent_message_queue_limited_to_one_line.md similarity index 100% rename from .storkit/work/6_archived/168_bug_agent_message_queue_limited_to_one_line.md rename to .huskies/work/6_archived/168_bug_agent_message_queue_limited_to_one_line.md diff --git a/.storkit/work/6_archived/170_story_add_test_first_requirements_to_agent_role_descriptions.md b/.huskies/work/6_archived/170_story_add_test_first_requirements_to_agent_role_descriptions.md similarity index 97% rename from .storkit/work/6_archived/170_story_add_test_first_requirements_to_agent_role_descriptions.md rename to .huskies/work/6_archived/170_story_add_test_first_requirements_to_agent_role_descriptions.md index f0f5a074..25f90979 100644 --- a/.storkit/work/6_archived/170_story_add_test_first_requirements_to_agent_role_descriptions.md +++ b/.huskies/work/6_archived/170_story_add_test_first_requirements_to_agent_role_descriptions.md @@ -21,7 +21,7 @@ As a project owner, I want agent role descriptions to explicitly require test-fi ## Test Results - + ### Unit Tests (3 passed, 0 failed) diff --git a/.storkit/work/6_archived/171_story_persist_test_results_to_story_files.md b/.huskies/work/6_archived/171_story_persist_test_results_to_story_files.md similarity index 94% rename from .storkit/work/6_archived/171_story_persist_test_results_to_story_files.md rename to .huskies/work/6_archived/171_story_persist_test_results_to_story_files.md index 3520bb71..824b76e4 100644 --- a/.storkit/work/6_archived/171_story_persist_test_results_to_story_files.md +++ b/.huskies/work/6_archived/171_story_persist_test_results_to_story_files.md @@ -22,7 +22,7 @@ As a project owner, I want test results written to the story markdown file when ## Test Results - + ### Unit Tests (1 passed, 0 failed) diff --git a/.storkit/work/6_archived/172_bug_setup_command_failure_prevents_agent_from_starting_creating_unrecoverable_deadlock.md b/.huskies/work/6_archived/172_bug_setup_command_failure_prevents_agent_from_starting_creating_unrecoverable_deadlock.md similarity index 100% rename from .storkit/work/6_archived/172_bug_setup_command_failure_prevents_agent_from_starting_creating_unrecoverable_deadlock.md rename to .huskies/work/6_archived/172_bug_setup_command_failure_prevents_agent_from_starting_creating_unrecoverable_deadlock.md diff --git a/.storkit/work/6_archived/173_bug_pipeline_board_lozenges_dont_update_on_agent_state_changes.md b/.huskies/work/6_archived/173_bug_pipeline_board_lozenges_dont_update_on_agent_state_changes.md similarity index 100% rename from .storkit/work/6_archived/173_bug_pipeline_board_lozenges_dont_update_on_agent_state_changes.md rename to .huskies/work/6_archived/173_bug_pipeline_board_lozenges_dont_update_on_agent_state_changes.md diff --git a/.storkit/work/6_archived/174_story_constrain_thinking_traces_in_chat_panel.md b/.huskies/work/6_archived/174_story_constrain_thinking_traces_in_chat_panel.md similarity index 100% rename from .storkit/work/6_archived/174_story_constrain_thinking_traces_in_chat_panel.md rename to .huskies/work/6_archived/174_story_constrain_thinking_traces_in_chat_panel.md diff --git a/.storkit/work/6_archived/174_story_matrix_chatbot_interface_for_story_kit.md b/.huskies/work/6_archived/174_story_matrix_chatbot_interface_for_story_kit.md similarity index 100% rename from .storkit/work/6_archived/174_story_matrix_chatbot_interface_for_story_kit.md rename to .huskies/work/6_archived/174_story_matrix_chatbot_interface_for_story_kit.md diff --git a/.storkit/work/6_archived/175_story_add_rust_test_coverage_reporting_with_cargo_llvm_cov.md b/.huskies/work/6_archived/175_story_add_rust_test_coverage_reporting_with_cargo_llvm_cov.md similarity index 100% rename from .storkit/work/6_archived/175_story_add_rust_test_coverage_reporting_with_cargo_llvm_cov.md rename to .huskies/work/6_archived/175_story_add_rust_test_coverage_reporting_with_cargo_llvm_cov.md diff --git a/.storkit/work/6_archived/176_bug_stories_moved_to_current_get_supervisor_instead_of_coder.md b/.huskies/work/6_archived/176_bug_stories_moved_to_current_get_supervisor_instead_of_coder.md similarity index 100% rename from .storkit/work/6_archived/176_bug_stories_moved_to_current_get_supervisor_instead_of_coder.md rename to .huskies/work/6_archived/176_bug_stories_moved_to_current_get_supervisor_instead_of_coder.md diff --git a/.storkit/work/6_archived/177_bug_no_mcp_tool_to_edit_story_acceptance_criteria.md b/.huskies/work/6_archived/177_bug_no_mcp_tool_to_edit_story_acceptance_criteria.md similarity index 98% rename from .storkit/work/6_archived/177_bug_no_mcp_tool_to_edit_story_acceptance_criteria.md rename to .huskies/work/6_archived/177_bug_no_mcp_tool_to_edit_story_acceptance_criteria.md index 49bda9e9..2aa252f8 100644 --- a/.storkit/work/6_archived/177_bug_no_mcp_tool_to_edit_story_acceptance_criteria.md +++ b/.huskies/work/6_archived/177_bug_no_mcp_tool_to_edit_story_acceptance_criteria.md @@ -26,4 +26,4 @@ An MCP tool (e.g. add_criterion or edit_story) that can add/remove/update accept - [ ] An MCP tool exists to add acceptance criteria to a story file - [ ] An MCP tool exists to update the story description or user story text -- [ ] These tools auto-commit changes to the story file like other storkit MCP tools do +- [ ] These tools auto-commit changes to the story file like other huskies MCP tools do diff --git a/.storkit/work/6_archived/178_story_fix_chat_textarea_input_lag.md b/.huskies/work/6_archived/178_story_fix_chat_textarea_input_lag.md similarity index 100% rename from .storkit/work/6_archived/178_story_fix_chat_textarea_input_lag.md rename to .huskies/work/6_archived/178_story_fix_chat_textarea_input_lag.md diff --git a/.storkit/work/6_archived/179_story_add_configurable_chat_history_pruning.md b/.huskies/work/6_archived/179_story_add_configurable_chat_history_pruning.md similarity index 100% rename from .storkit/work/6_archived/179_story_add_configurable_chat_history_pruning.md rename to .huskies/work/6_archived/179_story_add_configurable_chat_history_pruning.md diff --git a/.storkit/work/6_archived/17_story_display_remaining_context.md b/.huskies/work/6_archived/17_story_display_remaining_context.md similarity index 100% rename from .storkit/work/6_archived/17_story_display_remaining_context.md rename to .huskies/work/6_archived/17_story_display_remaining_context.md diff --git a/.storkit/work/6_archived/180_bug_web_ui_permissions_handling_unreliable.md b/.huskies/work/6_archived/180_bug_web_ui_permissions_handling_unreliable.md similarity index 100% rename from .storkit/work/6_archived/180_bug_web_ui_permissions_handling_unreliable.md rename to .huskies/work/6_archived/180_bug_web_ui_permissions_handling_unreliable.md diff --git a/.storkit/work/6_archived/181_story_live_pipeline_updates_in_matrix.md b/.huskies/work/6_archived/181_story_live_pipeline_updates_in_matrix.md similarity index 100% rename from .storkit/work/6_archived/181_story_live_pipeline_updates_in_matrix.md rename to .huskies/work/6_archived/181_story_live_pipeline_updates_in_matrix.md diff --git a/.storkit/work/6_archived/182_story_matrix_bot_conversation_context_and_multi_room.md b/.huskies/work/6_archived/182_story_matrix_bot_conversation_context_and_multi_room.md similarity index 100% rename from .storkit/work/6_archived/182_story_matrix_bot_conversation_context_and_multi_room.md rename to .huskies/work/6_archived/182_story_matrix_bot_conversation_context_and_multi_room.md diff --git a/.storkit/work/6_archived/183_story_refactor_matrix_bot_to_use_claude_code_provider_instead_of_direct_anthropic_api.md b/.huskies/work/6_archived/183_story_refactor_matrix_bot_to_use_claude_code_provider_instead_of_direct_anthropic_api.md similarity index 100% rename from .storkit/work/6_archived/183_story_refactor_matrix_bot_to_use_claude_code_provider_instead_of_direct_anthropic_api.md rename to .huskies/work/6_archived/183_story_refactor_matrix_bot_to_use_claude_code_provider_instead_of_direct_anthropic_api.md diff --git a/.storkit/work/6_archived/184_story_stream_bot_responses_to_matrix_on_double_newline_boundaries.md b/.huskies/work/6_archived/184_story_stream_bot_responses_to_matrix_on_double_newline_boundaries.md similarity index 100% rename from .storkit/work/6_archived/184_story_stream_bot_responses_to_matrix_on_double_newline_boundaries.md rename to .huskies/work/6_archived/184_story_stream_bot_responses_to_matrix_on_double_newline_boundaries.md diff --git a/.storkit/work/6_archived/185_bug_stale_completed_qa_agent_not_reaped_from_agent_list.md b/.huskies/work/6_archived/185_bug_stale_completed_qa_agent_not_reaped_from_agent_list.md similarity index 100% rename from .storkit/work/6_archived/185_bug_stale_completed_qa_agent_not_reaped_from_agent_list.md rename to .huskies/work/6_archived/185_bug_stale_completed_qa_agent_not_reaped_from_agent_list.md diff --git a/.storkit/work/6_archived/186_story_add_storkit_branding_to_header.md b/.huskies/work/6_archived/186_story_add_storkit_branding_to_header.md similarity index 100% rename from .storkit/work/6_archived/186_story_add_storkit_branding_to_header.md rename to .huskies/work/6_archived/186_story_add_storkit_branding_to_header.md diff --git a/.storkit/work/6_archived/187_story_preserve_queued_messages_in_chat_input_on_cancel.md b/.huskies/work/6_archived/187_story_preserve_queued_messages_in_chat_input_on_cancel.md similarity index 100% rename from .storkit/work/6_archived/187_story_preserve_queued_messages_in_chat_input_on_cancel.md rename to .huskies/work/6_archived/187_story_preserve_queued_messages_in_chat_input_on_cancel.md diff --git a/.storkit/work/6_archived/188_story_render_matrix_bot_messages_with_html_formatting.md b/.huskies/work/6_archived/188_story_render_matrix_bot_messages_with_html_formatting.md similarity index 100% rename from .storkit/work/6_archived/188_story_render_matrix_bot_messages_with_html_formatting.md rename to .huskies/work/6_archived/188_story_render_matrix_bot_messages_with_html_formatting.md diff --git a/.storkit/work/6_archived/189_story_surface_claude_code_compaction_notices_in_matrix_chat.md b/.huskies/work/6_archived/189_story_surface_claude_code_compaction_notices_in_matrix_chat.md similarity index 100% rename from .storkit/work/6_archived/189_story_surface_claude_code_compaction_notices_in_matrix_chat.md rename to .huskies/work/6_archived/189_story_surface_claude_code_compaction_notices_in_matrix_chat.md diff --git a/.storkit/work/6_archived/18_story_streaming_responses.md b/.huskies/work/6_archived/18_story_streaming_responses.md similarity index 100% rename from .storkit/work/6_archived/18_story_streaming_responses.md rename to .huskies/work/6_archived/18_story_streaming_responses.md diff --git a/.storkit/work/6_archived/190_story_auto_select_available_agent_for_stage_in_start_agent.md b/.huskies/work/6_archived/190_story_auto_select_available_agent_for_stage_in_start_agent.md similarity index 100% rename from .storkit/work/6_archived/190_story_auto_select_available_agent_for_stage_in_start_agent.md rename to .huskies/work/6_archived/190_story_auto_select_available_agent_for_stage_in_start_agent.md diff --git a/.storkit/work/6_archived/191_story_matrix_bot_should_only_respond_when_directly_addressed.md b/.huskies/work/6_archived/191_story_matrix_bot_should_only_respond_when_directly_addressed.md similarity index 91% rename from .storkit/work/6_archived/191_story_matrix_bot_should_only_respond_when_directly_addressed.md rename to .huskies/work/6_archived/191_story_matrix_bot_should_only_respond_when_directly_addressed.md index 96652dc9..ad371011 100644 --- a/.storkit/work/6_archived/191_story_matrix_bot_should_only_respond_when_directly_addressed.md +++ b/.huskies/work/6_archived/191_story_matrix_bot_should_only_respond_when_directly_addressed.md @@ -13,7 +13,7 @@ As a Matrix room participant, I want the bot to only respond when I address it w - [ ] Bot ignores messages that don't mention @timmy or the bot's Matrix user ID - [ ] Bot responds normally when mentioned with @timmy at the start or anywhere in the message - [ ] Bot still processes replies to its own messages (threaded replies) -- [ ] Existing command handling (storkit MCP tools, etc.) still works when the bot is addressed +- [ ] Existing command handling (huskies MCP tools, etc.) still works when the bot is addressed ## Out of Scope diff --git a/.storkit/work/6_archived/192_bug_code_fences_lose_newlines_when_pasted_from_agent_output.md b/.huskies/work/6_archived/192_bug_code_fences_lose_newlines_when_pasted_from_agent_output.md similarity index 100% rename from .storkit/work/6_archived/192_bug_code_fences_lose_newlines_when_pasted_from_agent_output.md rename to .huskies/work/6_archived/192_bug_code_fences_lose_newlines_when_pasted_from_agent_output.md diff --git a/.storkit/work/6_archived/193_story_clickable_code_references_in_frontend.md b/.huskies/work/6_archived/193_story_clickable_code_references_in_frontend.md similarity index 100% rename from .storkit/work/6_archived/193_story_clickable_code_references_in_frontend.md rename to .huskies/work/6_archived/193_story_clickable_code_references_in_frontend.md diff --git a/.storkit/work/6_archived/194_story_enable_matrix_e2ee_with_cross_signing_verification_on_bot.md b/.huskies/work/6_archived/194_story_enable_matrix_e2ee_with_cross_signing_verification_on_bot.md similarity index 100% rename from .storkit/work/6_archived/194_story_enable_matrix_e2ee_with_cross_signing_verification_on_bot.md rename to .huskies/work/6_archived/194_story_enable_matrix_e2ee_with_cross_signing_verification_on_bot.md diff --git a/.storkit/work/6_archived/195_story_preserve_newlines_in_chat_message_submission.md b/.huskies/work/6_archived/195_story_preserve_newlines_in_chat_message_submission.md similarity index 100% rename from .storkit/work/6_archived/195_story_preserve_newlines_in_chat_message_submission.md rename to .huskies/work/6_archived/195_story_preserve_newlines_in_chat_message_submission.md diff --git a/.storkit/work/6_archived/196_story_render_code_fences_in_user_chat_messages.md b/.huskies/work/6_archived/196_story_render_code_fences_in_user_chat_messages.md similarity index 100% rename from .storkit/work/6_archived/196_story_render_code_fences_in_user_chat_messages.md rename to .huskies/work/6_archived/196_story_render_code_fences_in_user_chat_messages.md diff --git a/.storkit/work/6_archived/197_bug_cancel_button_discards_queued_messages_instead_of_preserving_them_in_chat_input.md b/.huskies/work/6_archived/197_bug_cancel_button_discards_queued_messages_instead_of_preserving_them_in_chat_input.md similarity index 100% rename from .storkit/work/6_archived/197_bug_cancel_button_discards_queued_messages_instead_of_preserving_them_in_chat_input.md rename to .huskies/work/6_archived/197_bug_cancel_button_discards_queued_messages_instead_of_preserving_them_in_chat_input.md diff --git a/.storkit/work/6_archived/198_story_distinguish_work_item_types_in_web_ui.md b/.huskies/work/6_archived/198_story_distinguish_work_item_types_in_web_ui.md similarity index 100% rename from .storkit/work/6_archived/198_story_distinguish_work_item_types_in_web_ui.md rename to .huskies/work/6_archived/198_story_distinguish_work_item_types_in_web_ui.md diff --git a/.storkit/work/6_archived/199_story_web_ui_submits_all_queued_items_at_once.md b/.huskies/work/6_archived/199_story_web_ui_submits_all_queued_items_at_once.md similarity index 100% rename from .storkit/work/6_archived/199_story_web_ui_submits_all_queued_items_at_once.md rename to .huskies/work/6_archived/199_story_web_ui_submits_all_queued_items_at_once.md diff --git a/.storkit/work/6_archived/1_bug_anthropic_models_fetch_without_key.md b/.huskies/work/6_archived/1_bug_anthropic_models_fetch_without_key.md similarity index 100% rename from .storkit/work/6_archived/1_bug_anthropic_models_fetch_without_key.md rename to .huskies/work/6_archived/1_bug_anthropic_models_fetch_without_key.md diff --git a/.storkit/work/6_archived/200_story_auto_prune_worktrees_for_archived_stories_in_watcher_sweep.md b/.huskies/work/6_archived/200_story_auto_prune_worktrees_for_archived_stories_in_watcher_sweep.md similarity index 100% rename from .storkit/work/6_archived/200_story_auto_prune_worktrees_for_archived_stories_in_watcher_sweep.md rename to .huskies/work/6_archived/200_story_auto_prune_worktrees_for_archived_stories_in_watcher_sweep.md diff --git a/.storkit/work/6_archived/201_story_make_watcher_sweep_interval_configurable_via_project_toml.md b/.huskies/work/6_archived/201_story_make_watcher_sweep_interval_configurable_via_project_toml.md similarity index 100% rename from .storkit/work/6_archived/201_story_make_watcher_sweep_interval_configurable_via_project_toml.md rename to .huskies/work/6_archived/201_story_make_watcher_sweep_interval_configurable_via_project_toml.md diff --git a/.storkit/work/6_archived/202_story_make_agent_watchdog_interval_configurable_via_project_toml.md b/.huskies/work/6_archived/202_story_make_agent_watchdog_interval_configurable_via_project_toml.md similarity index 100% rename from .storkit/work/6_archived/202_story_make_agent_watchdog_interval_configurable_via_project_toml.md rename to .huskies/work/6_archived/202_story_make_agent_watchdog_interval_configurable_via_project_toml.md diff --git a/.storkit/work/6_archived/203_story_move_story_to_current_before_checking_agent_availability_in_start_agent.md b/.huskies/work/6_archived/203_story_move_story_to_current_before_checking_agent_availability_in_start_agent.md similarity index 100% rename from .storkit/work/6_archived/203_story_move_story_to_current_before_checking_agent_availability_in_start_agent.md rename to .huskies/work/6_archived/203_story_move_story_to_current_before_checking_agent_availability_in_start_agent.md diff --git a/.storkit/work/6_archived/204_story_rename_storkit_branding_to_story_kit.md b/.huskies/work/6_archived/204_story_rename_storkit_branding_to_story_kit.md similarity index 100% rename from .storkit/work/6_archived/204_story_rename_storkit_branding_to_story_kit.md rename to .huskies/work/6_archived/204_story_rename_storkit_branding_to_story_kit.md diff --git a/.storkit/work/6_archived/205_bug_mergemaster_marks_stories_as_done_without_squash_merging_code.md b/.huskies/work/6_archived/205_bug_mergemaster_marks_stories_as_done_without_squash_merging_code.md similarity index 96% rename from .storkit/work/6_archived/205_bug_mergemaster_marks_stories_as_done_without_squash_merging_code.md rename to .huskies/work/6_archived/205_bug_mergemaster_marks_stories_as_done_without_squash_merging_code.md index 4c3bb4f5..b02dae79 100644 --- a/.storkit/work/6_archived/205_bug_mergemaster_marks_stories_as_done_without_squash_merging_code.md +++ b/.huskies/work/6_archived/205_bug_mergemaster_marks_stories_as_done_without_squash_merging_code.md @@ -14,7 +14,7 @@ The new merge-queue worktree approach (introduced ~24 hours ago) has a race cond 1. `run_squash_merge()` creates a `merge-queue/{story_id}` branch at master's current HEAD 2. It creates a temporary worktree, runs `git merge --squash`, commits, and runs quality gates — all in the merge-queue worktree -3. Meanwhile, the **filesystem watcher auto-commits pipeline file moves** to master (e.g. "storkit: queue X for merge", "storkit: done Y") +3. Meanwhile, the **filesystem watcher auto-commits pipeline file moves** to master (e.g. "huskies: queue X for merge", "huskies: done Y") 4. By the time step 7 tries `git merge --ff-only merge-queue/{story_id}` on master, master has diverged and the fast-forward fails 5. `run_squash_merge()` returns `success: false` (correctly) but `gates_passed: true` (misleading) 6. The `merge_agent_work` caller correctly reports failure — but the mergemaster is a Claude Code agent, not the Rust pipeline. The agent sees the failure, gives up on the squash merge, and instead manually moves the story file to done without the code @@ -39,7 +39,7 @@ The stale `.story_kit/merge_workspace` directory from failed merges blocks subse ## Actual Result -Stories are moved to 5_done with pipeline commit messages like "storkit: done ..." but the feature branch code is never squash-merged onto master. Feature branches retain unmerged commits. +Stories are moved to 5_done with pipeline commit messages like "huskies: done ..." but the feature branch code is never squash-merged onto master. Feature branches retain unmerged commits. ## Expected Result diff --git a/.storkit/work/6_archived/206_story_claude_pty_should_be_selected_by_default_on_first_use.md b/.huskies/work/6_archived/206_story_claude_pty_should_be_selected_by_default_on_first_use.md similarity index 100% rename from .storkit/work/6_archived/206_story_claude_pty_should_be_selected_by_default_on_first_use.md rename to .huskies/work/6_archived/206_story_claude_pty_should_be_selected_by_default_on_first_use.md diff --git a/.storkit/work/6_archived/207_story_rename_llm_provider_labels_claude_pty_to_claude_code_anthropic_to_anthropic_api.md b/.huskies/work/6_archived/207_story_rename_llm_provider_labels_claude_pty_to_claude_code_anthropic_to_anthropic_api.md similarity index 100% rename from .storkit/work/6_archived/207_story_rename_llm_provider_labels_claude_pty_to_claude_code_anthropic_to_anthropic_api.md rename to .huskies/work/6_archived/207_story_rename_llm_provider_labels_claude_pty_to_claude_code_anthropic_to_anthropic_api.md diff --git a/.storkit/work/6_archived/208_bug_project_scaffold_does_not_write_mcp_json_to_project_root.md b/.huskies/work/6_archived/208_bug_project_scaffold_does_not_write_mcp_json_to_project_root.md similarity index 82% rename from .storkit/work/6_archived/208_bug_project_scaffold_does_not_write_mcp_json_to_project_root.md rename to .huskies/work/6_archived/208_bug_project_scaffold_does_not_write_mcp_json_to_project_root.md index a78f6d1b..a6b148f0 100644 --- a/.storkit/work/6_archived/208_bug_project_scaffold_does_not_write_mcp_json_to_project_root.md +++ b/.huskies/work/6_archived/208_bug_project_scaffold_does_not_write_mcp_json_to_project_root.md @@ -6,24 +6,24 @@ name: "Project scaffold does not write .mcp.json to project root" ## Description -When a new project is opened/scaffolded, `.mcp.json` is not written to the project root. The `write_mcp_json()` function (worktree.rs:6) is only called during worktree creation, not during `scaffold_story_kit()` (io/fs.rs:464) or `open_project()` (io/fs.rs:503). This means claude-pty spawned with `--permission-prompt-tool mcp__storkit__prompt_permission` immediately fails because the MCP tool isn't available. +When a new project is opened/scaffolded, `.mcp.json` is not written to the project root. The `write_mcp_json()` function (worktree.rs:6) is only called during worktree creation, not during `scaffold_story_kit()` (io/fs.rs:464) or `open_project()` (io/fs.rs:503). This means claude-pty spawned with `--permission-prompt-tool mcp__huskies__prompt_permission` immediately fails because the MCP tool isn't available. Additionally, there is no way for the user to trigger scaffolding from the CLI — `find_story_kit_root()` in main.rs falls through without scaffolding if `.story_kit/` doesn't exist yet, so the only path is via the UI file chooser. ## How to Reproduce 1. Create an empty directory or navigate to a project without `.story_kit/` -2. Run `storkit` +2. Run `huskies` 3. Open the project via the UI file chooser 4. Try to chat using the claude-code provider ## Actual Result -Claude Code exits immediately with: `Error: MCP tool mcp__storkit__prompt_permission (passed via --permission-prompt-tool) not found. Available MCP tools: none` +Claude Code exits immediately with: `Error: MCP tool mcp__huskies__prompt_permission (passed via --permission-prompt-tool) not found. Available MCP tools: none` ## Expected Result -`.mcp.json` is written to the project root during scaffolding/open, so claude-code can connect to the storkit MCP server. +`.mcp.json` is written to the project root during scaffolding/open, so claude-code can connect to the huskies MCP server. ## Acceptance Criteria diff --git a/.storkit/work/6_archived/209_story_accept_optional_positional_path_argument_on_startup.md b/.huskies/work/6_archived/209_story_accept_optional_positional_path_argument_on_startup.md similarity index 63% rename from .storkit/work/6_archived/209_story_accept_optional_positional_path_argument_on_startup.md rename to .huskies/work/6_archived/209_story_accept_optional_positional_path_argument_on_startup.md index 2b2f8532..d7721a4a 100644 --- a/.storkit/work/6_archived/209_story_accept_optional_positional_path_argument_on_startup.md +++ b/.huskies/work/6_archived/209_story_accept_optional_positional_path_argument_on_startup.md @@ -6,13 +6,13 @@ name: "Accept optional positional path argument on startup" ## User Story -As a user, I want to run `storkit .` or `storkit /path/to/project` to start the server with that directory as the project, so that I don't have to use the UI file chooser. +As a user, I want to run `huskies .` or `huskies /path/to/project` to start the server with that directory as the project, so that I don't have to use the UI file chooser. ## Acceptance Criteria -- [ ] Running `storkit` with no args behaves as today (auto-detect from cwd) -- [ ] Running `storkit .` opens the current directory as the project -- [ ] Running `storkit /some/path` opens that path as the project +- [ ] Running `huskies` with no args behaves as today (auto-detect from cwd) +- [ ] Running `huskies .` opens the current directory as the project +- [ ] Running `huskies /some/path` opens that path as the project - [ ] If the path has no .story_kit/, it is scaffolded automatically - [ ] Invalid paths produce a clear error message diff --git a/.storkit/work/6_archived/20_story_start_new_session.md b/.huskies/work/6_archived/20_story_start_new_session.md similarity index 100% rename from .storkit/work/6_archived/20_story_start_new_session.md rename to .huskies/work/6_archived/20_story_start_new_session.md diff --git a/.storkit/work/6_archived/210_bug_pipeline_moves_story_to_done_even_when_mergemaster_reports_merge_failure.md b/.huskies/work/6_archived/210_bug_pipeline_moves_story_to_done_even_when_mergemaster_reports_merge_failure.md similarity index 100% rename from .storkit/work/6_archived/210_bug_pipeline_moves_story_to_done_even_when_mergemaster_reports_merge_failure.md rename to .huskies/work/6_archived/210_bug_pipeline_moves_story_to_done_even_when_mergemaster_reports_merge_failure.md diff --git a/.storkit/work/6_archived/211_story_skip_selection_screen_when_cli_path_argument_provided.md b/.huskies/work/6_archived/211_story_skip_selection_screen_when_cli_path_argument_provided.md similarity index 92% rename from .storkit/work/6_archived/211_story_skip_selection_screen_when_cli_path_argument_provided.md rename to .huskies/work/6_archived/211_story_skip_selection_screen_when_cli_path_argument_provided.md index b533cb2a..f40b9154 100644 --- a/.storkit/work/6_archived/211_story_skip_selection_screen_when_cli_path_argument_provided.md +++ b/.huskies/work/6_archived/211_story_skip_selection_screen_when_cli_path_argument_provided.md @@ -6,7 +6,7 @@ name: "Skip selection screen when CLI path argument provided" ## User Story -As a user, I want the frontend to go straight to the project workspace when I start the server with an explicit path argument (e.g. `storkit .`), so that I don't have to click through the selection screen for a project the server already opened. +As a user, I want the frontend to go straight to the project workspace when I start the server with an explicit path argument (e.g. `huskies .`), so that I don't have to click through the selection screen for a project the server already opened. ## Acceptance Criteria diff --git a/.storkit/work/6_archived/213_story_remove_colored_left_border_from_work_item_cards.md b/.huskies/work/6_archived/213_story_remove_colored_left_border_from_work_item_cards.md similarity index 100% rename from .storkit/work/6_archived/213_story_remove_colored_left_border_from_work_item_cards.md rename to .huskies/work/6_archived/213_story_remove_colored_left_border_from_work_item_cards.md diff --git a/.storkit/work/6_archived/214_story_scaffold_creates_complete_project_structure.md b/.huskies/work/6_archived/214_story_scaffold_creates_complete_project_structure.md similarity index 100% rename from .storkit/work/6_archived/214_story_scaffold_creates_complete_project_structure.md rename to .huskies/work/6_archived/214_story_scaffold_creates_complete_project_structure.md diff --git a/.storkit/work/6_archived/215_bug_cancel_button_still_discards_queued_messages_197_regression.md b/.huskies/work/6_archived/215_bug_cancel_button_still_discards_queued_messages_197_regression.md similarity index 100% rename from .storkit/work/6_archived/215_bug_cancel_button_still_discards_queued_messages_197_regression.md rename to .huskies/work/6_archived/215_bug_cancel_button_still_discards_queued_messages_197_regression.md diff --git a/.storkit/work/6_archived/216_story_merge_quality_gates_should_use_project_toml_components_and_script_test_instead_of_hardcoded_frontend_pnpm.md b/.huskies/work/6_archived/216_story_merge_quality_gates_should_use_project_toml_components_and_script_test_instead_of_hardcoded_frontend_pnpm.md similarity index 100% rename from .storkit/work/6_archived/216_story_merge_quality_gates_should_use_project_toml_components_and_script_test_instead_of_hardcoded_frontend_pnpm.md rename to .huskies/work/6_archived/216_story_merge_quality_gates_should_use_project_toml_components_and_script_test_instead_of_hardcoded_frontend_pnpm.md diff --git a/.storkit/work/6_archived/217_story_scaffold_generates_claude_md.md b/.huskies/work/6_archived/217_story_scaffold_generates_claude_md.md similarity index 92% rename from .storkit/work/6_archived/217_story_scaffold_generates_claude_md.md rename to .huskies/work/6_archived/217_story_scaffold_generates_claude_md.md index c37252b2..f4dadb5c 100644 --- a/.storkit/work/6_archived/217_story_scaffold_generates_claude_md.md +++ b/.huskies/work/6_archived/217_story_scaffold_generates_claude_md.md @@ -14,7 +14,7 @@ As a developer setting up a new project with Story Kit, I want the scaffold to g - [ ] CLAUDE.md includes a directive to read .story_kit/README.md for the dev process - [ ] Scaffold does not overwrite an existing CLAUDE.md (consistent with other scaffold files) - [ ] Onboarding status does not check CLAUDE.md (it is not a required onboarding step) -- [ ] CLAUDE.md content matches the storkit-app's own CLAUDE.md (command chaining rule + read .story_kit/README.md directive), prefixed with the scaffold sentinel +- [ ] CLAUDE.md content matches the huskies-app's own CLAUDE.md (command chaining rule + read .story_kit/README.md directive), prefixed with the scaffold sentinel ## Out of Scope diff --git a/.storkit/work/6_archived/218_story_hide_thinking_traces_from_agents_panel.md b/.huskies/work/6_archived/218_story_hide_thinking_traces_from_agents_panel.md similarity index 100% rename from .storkit/work/6_archived/218_story_hide_thinking_traces_from_agents_panel.md rename to .huskies/work/6_archived/218_story_hide_thinking_traces_from_agents_panel.md diff --git a/.storkit/work/6_archived/219_story_add_always_allow_option_to_web_ui_permission_dialog.md b/.huskies/work/6_archived/219_story_add_always_allow_option_to_web_ui_permission_dialog.md similarity index 91% rename from .storkit/work/6_archived/219_story_add_always_allow_option_to_web_ui_permission_dialog.md rename to .huskies/work/6_archived/219_story_add_always_allow_option_to_web_ui_permission_dialog.md index 794688b4..a2346d04 100644 --- a/.storkit/work/6_archived/219_story_add_always_allow_option_to_web_ui_permission_dialog.md +++ b/.huskies/work/6_archived/219_story_add_always_allow_option_to_web_ui_permission_dialog.md @@ -15,7 +15,7 @@ As a user interacting with agents via the web UI, I want an "Always Allow" optio - [ ] After Always Allow, Claude Code's built-in permission system handles future checks without calling the prompt tool - [ ] Edit and Write rules use the tool name (e.g. Edit, Write) - [ ] Bash rules use the command prefix pattern (e.g. Bash(git *)) -- [ ] MCP tool rules use the tool name pattern (e.g. mcp__storkit__create_story) +- [ ] MCP tool rules use the tool name pattern (e.g. mcp__huskies__create_story) - [ ] Existing rules in settings.json are not duplicated ## Out of Scope diff --git a/.storkit/work/6_archived/220_story_acceptance_gates_in_current_stage_should_use_script_test_instead_of_hardcoded_cargo_clippy.md b/.huskies/work/6_archived/220_story_acceptance_gates_in_current_stage_should_use_script_test_instead_of_hardcoded_cargo_clippy.md similarity index 100% rename from .storkit/work/6_archived/220_story_acceptance_gates_in_current_stage_should_use_script_test_instead_of_hardcoded_cargo_clippy.md rename to .huskies/work/6_archived/220_story_acceptance_gates_in_current_stage_should_use_script_test_instead_of_hardcoded_cargo_clippy.md diff --git a/.storkit/work/6_archived/221_story_replace_llm_driven_qa_stage_with_deterministic_rust_pipeline.md b/.huskies/work/6_archived/221_story_replace_llm_driven_qa_stage_with_deterministic_rust_pipeline.md similarity index 100% rename from .storkit/work/6_archived/221_story_replace_llm_driven_qa_stage_with_deterministic_rust_pipeline.md rename to .huskies/work/6_archived/221_story_replace_llm_driven_qa_stage_with_deterministic_rust_pipeline.md diff --git a/.storkit/work/6_archived/222_story_scaffolded_agent_permissions_should_be_tech_stack_agnostic.md b/.huskies/work/6_archived/222_story_scaffolded_agent_permissions_should_be_tech_stack_agnostic.md similarity index 100% rename from .storkit/work/6_archived/222_story_scaffolded_agent_permissions_should_be_tech_stack_agnostic.md rename to .huskies/work/6_archived/222_story_scaffolded_agent_permissions_should_be_tech_stack_agnostic.md diff --git a/.storkit/work/6_archived/223_bug_qa_agent_not_stopped_when_story_moves_to_merge_stage.md b/.huskies/work/6_archived/223_bug_qa_agent_not_stopped_when_story_moves_to_merge_stage.md similarity index 100% rename from .storkit/work/6_archived/223_bug_qa_agent_not_stopped_when_story_moves_to_merge_stage.md rename to .huskies/work/6_archived/223_bug_qa_agent_not_stopped_when_story_moves_to_merge_stage.md diff --git a/.storkit/work/6_archived/224_story_expand_work_item_to_full_screen_detail_view.md b/.huskies/work/6_archived/224_story_expand_work_item_to_full_screen_detail_view.md similarity index 100% rename from .storkit/work/6_archived/224_story_expand_work_item_to_full_screen_detail_view.md rename to .huskies/work/6_archived/224_story_expand_work_item_to_full_screen_detail_view.md diff --git a/.storkit/work/6_archived/225_story_surface_merge_conflicts_and_failures_in_the_web_ui.md b/.huskies/work/6_archived/225_story_surface_merge_conflicts_and_failures_in_the_web_ui.md similarity index 100% rename from .storkit/work/6_archived/225_story_surface_merge_conflicts_and_failures_in_the_web_ui.md rename to .huskies/work/6_archived/225_story_surface_merge_conflicts_and_failures_in_the_web_ui.md diff --git a/.storkit/work/6_archived/226_bug_mergemaster_accepts_stories_without_squash_merging_code.md b/.huskies/work/6_archived/226_bug_mergemaster_accepts_stories_without_squash_merging_code.md similarity index 100% rename from .storkit/work/6_archived/226_bug_mergemaster_accepts_stories_without_squash_merging_code.md rename to .huskies/work/6_archived/226_bug_mergemaster_accepts_stories_without_squash_merging_code.md diff --git a/.storkit/work/6_archived/227_bug_thinking_traces_visible_in_agents_panel_in_release_builds_only.md b/.huskies/work/6_archived/227_bug_thinking_traces_visible_in_agents_panel_in_release_builds_only.md similarity index 100% rename from .storkit/work/6_archived/227_bug_thinking_traces_visible_in_agents_panel_in_release_builds_only.md rename to .huskies/work/6_archived/227_bug_thinking_traces_visible_in_agents_panel_in_release_builds_only.md diff --git a/.storkit/work/6_archived/228_story_auto_detect_tech_stack_and_generate_component_sections_during_scaffolding.md b/.huskies/work/6_archived/228_story_auto_detect_tech_stack_and_generate_component_sections_during_scaffolding.md similarity index 100% rename from .storkit/work/6_archived/228_story_auto_detect_tech_stack_and_generate_component_sections_during_scaffolding.md rename to .huskies/work/6_archived/228_story_auto_detect_tech_stack_and_generate_component_sections_during_scaffolding.md diff --git a/.storkit/work/6_archived/229_story_coder_agents_should_check_off_acceptance_criteria_as_they_fulfill_them.md b/.huskies/work/6_archived/229_story_coder_agents_should_check_off_acceptance_criteria_as_they_fulfill_them.md similarity index 100% rename from .storkit/work/6_archived/229_story_coder_agents_should_check_off_acceptance_criteria_as_they_fulfill_them.md rename to .huskies/work/6_archived/229_story_coder_agents_should_check_off_acceptance_criteria_as_they_fulfill_them.md diff --git a/.storkit/work/6_archived/22_story_smart_autoscroll.md b/.huskies/work/6_archived/22_story_smart_autoscroll.md similarity index 100% rename from .storkit/work/6_archived/22_story_smart_autoscroll.md rename to .huskies/work/6_archived/22_story_smart_autoscroll.md diff --git a/.storkit/work/6_archived/230_story_prevent_duplicate_stage_agents_on_same_story.md b/.huskies/work/6_archived/230_story_prevent_duplicate_stage_agents_on_same_story.md similarity index 100% rename from .storkit/work/6_archived/230_story_prevent_duplicate_stage_agents_on_same_story.md rename to .huskies/work/6_archived/230_story_prevent_duplicate_stage_agents_on_same_story.md diff --git a/.storkit/work/6_archived/231_bug_agent_silently_disappears_when_worktree_creation_fails.md b/.huskies/work/6_archived/231_bug_agent_silently_disappears_when_worktree_creation_fails.md similarity index 100% rename from .storkit/work/6_archived/231_bug_agent_silently_disappears_when_worktree_creation_fails.md rename to .huskies/work/6_archived/231_bug_agent_silently_disappears_when_worktree_creation_fails.md diff --git a/.storkit/work/6_archived/232_story_fix_incorrect_bug_tool_descriptions_in_mcp_tools_list.md b/.huskies/work/6_archived/232_story_fix_incorrect_bug_tool_descriptions_in_mcp_tools_list.md similarity index 100% rename from .storkit/work/6_archived/232_story_fix_incorrect_bug_tool_descriptions_in_mcp_tools_list.md rename to .huskies/work/6_archived/232_story_fix_incorrect_bug_tool_descriptions_in_mcp_tools_list.md diff --git a/.storkit/work/6_archived/233_story_auto_assign_backoff_for_failed_merge_items.md b/.huskies/work/6_archived/233_story_auto_assign_backoff_for_failed_merge_items.md similarity index 100% rename from .storkit/work/6_archived/233_story_auto_assign_backoff_for_failed_merge_items.md rename to .huskies/work/6_archived/233_story_auto_assign_backoff_for_failed_merge_items.md diff --git a/.storkit/work/6_archived/235_story_show_agent_logs_for_a_story_in_expanded_work_item.md b/.huskies/work/6_archived/235_story_show_agent_logs_for_a_story_in_expanded_work_item.md similarity index 96% rename from .storkit/work/6_archived/235_story_show_agent_logs_for_a_story_in_expanded_work_item.md rename to .huskies/work/6_archived/235_story_show_agent_logs_for_a_story_in_expanded_work_item.md index 6d596519..53d2c28e 100644 --- a/.storkit/work/6_archived/235_story_show_agent_logs_for_a_story_in_expanded_work_item.md +++ b/.huskies/work/6_archived/235_story_show_agent_logs_for_a_story_in_expanded_work_item.md @@ -20,7 +20,7 @@ As a user, I want to see agent logs for a story inside its expanded view, so tha ## Test Results - + ### Unit Tests (9 passed, 0 failed) diff --git a/.storkit/work/6_archived/236_story_show_test_results_for_a_story_in_expanded_work_item.md b/.huskies/work/6_archived/236_story_show_test_results_for_a_story_in_expanded_work_item.md similarity index 92% rename from .storkit/work/6_archived/236_story_show_test_results_for_a_story_in_expanded_work_item.md rename to .huskies/work/6_archived/236_story_show_test_results_for_a_story_in_expanded_work_item.md index 31a08445..cb6dba7a 100644 --- a/.storkit/work/6_archived/236_story_show_test_results_for_a_story_in_expanded_work_item.md +++ b/.huskies/work/6_archived/236_story_show_test_results_for_a_story_in_expanded_work_item.md @@ -20,7 +20,7 @@ As a user, I want to see test results for a story inside its expanded view, so t ## Test Results - + ### Unit Tests (1 passed, 0 failed) diff --git a/.storkit/work/6_archived/237_bug_work_item_titles_render_too_large_in_expanded_view.md b/.huskies/work/6_archived/237_bug_work_item_titles_render_too_large_in_expanded_view.md similarity index 100% rename from .storkit/work/6_archived/237_bug_work_item_titles_render_too_large_in_expanded_view.md rename to .huskies/work/6_archived/237_bug_work_item_titles_render_too_large_in_expanded_view.md diff --git a/.storkit/work/6_archived/238_story_mergemaster_handles_merge_conflicts_by_resolving_them_automatically.md b/.huskies/work/6_archived/238_story_mergemaster_handles_merge_conflicts_by_resolving_them_automatically.md similarity index 100% rename from .storkit/work/6_archived/238_story_mergemaster_handles_merge_conflicts_by_resolving_them_automatically.md rename to .huskies/work/6_archived/238_story_mergemaster_handles_merge_conflicts_by_resolving_them_automatically.md diff --git a/.storkit/work/6_archived/23_story_alphabetize_llm_dropdown.md b/.huskies/work/6_archived/23_story_alphabetize_llm_dropdown.md similarity index 100% rename from .storkit/work/6_archived/23_story_alphabetize_llm_dropdown.md rename to .huskies/work/6_archived/23_story_alphabetize_llm_dropdown.md diff --git a/.storkit/work/6_archived/240_story_btw_side_question_slash_command.md b/.huskies/work/6_archived/240_story_btw_side_question_slash_command.md similarity index 100% rename from .storkit/work/6_archived/240_story_btw_side_question_slash_command.md rename to .huskies/work/6_archived/240_story_btw_side_question_slash_command.md diff --git a/.storkit/work/6_archived/241_story_help_slash_command.md b/.huskies/work/6_archived/241_story_help_slash_command.md similarity index 100% rename from .storkit/work/6_archived/241_story_help_slash_command.md rename to .huskies/work/6_archived/241_story_help_slash_command.md diff --git a/.storkit/work/6_archived/242_story_status_slash_command.md b/.huskies/work/6_archived/242_story_status_slash_command.md similarity index 100% rename from .storkit/work/6_archived/242_story_status_slash_command.md rename to .huskies/work/6_archived/242_story_status_slash_command.md diff --git a/.storkit/work/6_archived/243_bug_replace_pnpm_with_npm.md b/.huskies/work/6_archived/243_bug_replace_pnpm_with_npm.md similarity index 100% rename from .storkit/work/6_archived/243_bug_replace_pnpm_with_npm.md rename to .huskies/work/6_archived/243_bug_replace_pnpm_with_npm.md diff --git a/.storkit/work/6_archived/245_bug_chat_history_persistence_lost_on_page_refresh_story_145_regression.md b/.huskies/work/6_archived/245_bug_chat_history_persistence_lost_on_page_refresh_story_145_regression.md similarity index 100% rename from .storkit/work/6_archived/245_bug_chat_history_persistence_lost_on_page_refresh_story_145_regression.md rename to .huskies/work/6_archived/245_bug_chat_history_persistence_lost_on_page_refresh_story_145_regression.md diff --git a/.storkit/work/6_archived/246_story_enforce_cryptographic_identity_verification_for_matrix_commands.md b/.huskies/work/6_archived/246_story_enforce_cryptographic_identity_verification_for_matrix_commands.md similarity index 100% rename from .storkit/work/6_archived/246_story_enforce_cryptographic_identity_verification_for_matrix_commands.md rename to .huskies/work/6_archived/246_story_enforce_cryptographic_identity_verification_for_matrix_commands.md diff --git a/.storkit/work/6_archived/247_story_human_qa_gate_with_rejection_flow.md b/.huskies/work/6_archived/247_story_human_qa_gate_with_rejection_flow.md similarity index 100% rename from .storkit/work/6_archived/247_story_human_qa_gate_with_rejection_flow.md rename to .huskies/work/6_archived/247_story_human_qa_gate_with_rejection_flow.md diff --git a/.storkit/work/6_archived/248_bug_chat_does_not_auto_scroll_to_new_messages.md b/.huskies/work/6_archived/248_bug_chat_does_not_auto_scroll_to_new_messages.md similarity index 100% rename from .storkit/work/6_archived/248_bug_chat_does_not_auto_scroll_to_new_messages.md rename to .huskies/work/6_archived/248_bug_chat_does_not_auto_scroll_to_new_messages.md diff --git a/.storkit/work/6_archived/249_story_agent_assignment_via_story_front_matter.md b/.huskies/work/6_archived/249_story_agent_assignment_via_story_front_matter.md similarity index 100% rename from .storkit/work/6_archived/249_story_agent_assignment_via_story_front_matter.md rename to .huskies/work/6_archived/249_story_agent_assignment_via_story_front_matter.md diff --git a/.storkit/work/6_archived/24_story_tauri_to_browser_ui.md b/.huskies/work/6_archived/24_story_tauri_to_browser_ui.md similarity index 100% rename from .storkit/work/6_archived/24_story_tauri_to_browser_ui.md rename to .huskies/work/6_archived/24_story_tauri_to_browser_ui.md diff --git a/.storkit/work/6_archived/250_bug_merge_pipeline_cherry_pick_fails_with_bad_revision_on_merge_queue_branch.md b/.huskies/work/6_archived/250_bug_merge_pipeline_cherry_pick_fails_with_bad_revision_on_merge_queue_branch.md similarity index 100% rename from .storkit/work/6_archived/250_bug_merge_pipeline_cherry_pick_fails_with_bad_revision_on_merge_queue_branch.md rename to .huskies/work/6_archived/250_bug_merge_pipeline_cherry_pick_fails_with_bad_revision_on_merge_queue_branch.md diff --git a/.storkit/work/6_archived/251_bug_archive_sweep_not_moving_stories_from_done_to_archived.md b/.huskies/work/6_archived/251_bug_archive_sweep_not_moving_stories_from_done_to_archived.md similarity index 100% rename from .storkit/work/6_archived/251_bug_archive_sweep_not_moving_stories_from_done_to_archived.md rename to .huskies/work/6_archived/251_bug_archive_sweep_not_moving_stories_from_done_to_archived.md diff --git a/.storkit/work/6_archived/252_story_coder_agents_must_find_root_causes_for_bugs.md b/.huskies/work/6_archived/252_story_coder_agents_must_find_root_causes_for_bugs.md similarity index 100% rename from .storkit/work/6_archived/252_story_coder_agents_must_find_root_causes_for_bugs.md rename to .huskies/work/6_archived/252_story_coder_agents_must_find_root_causes_for_bugs.md diff --git a/.storkit/work/6_archived/253_bug_watcher_and_auto_assign_do_not_reinitialize_when_project_root_changes.md b/.huskies/work/6_archived/253_bug_watcher_and_auto_assign_do_not_reinitialize_when_project_root_changes.md similarity index 100% rename from .storkit/work/6_archived/253_bug_watcher_and_auto_assign_do_not_reinitialize_when_project_root_changes.md rename to .huskies/work/6_archived/253_bug_watcher_and_auto_assign_do_not_reinitialize_when_project_root_changes.md diff --git a/.storkit/work/6_archived/254_story_add_refactor_work_item_type.md b/.huskies/work/6_archived/254_story_add_refactor_work_item_type.md similarity index 100% rename from .storkit/work/6_archived/254_story_add_refactor_work_item_type.md rename to .huskies/work/6_archived/254_story_add_refactor_work_item_type.md diff --git a/.storkit/work/6_archived/255_story_show_agent_logs_in_expanded_story_popup.md b/.huskies/work/6_archived/255_story_show_agent_logs_in_expanded_story_popup.md similarity index 100% rename from .storkit/work/6_archived/255_story_show_agent_logs_in_expanded_story_popup.md rename to .huskies/work/6_archived/255_story_show_agent_logs_in_expanded_story_popup.md diff --git a/.storkit/work/6_archived/256_story_bot_must_verify_other_users_cross_signing_identity_before_checking_device_verification.md b/.huskies/work/6_archived/256_story_bot_must_verify_other_users_cross_signing_identity_before_checking_device_verification.md similarity index 96% rename from .storkit/work/6_archived/256_story_bot_must_verify_other_users_cross_signing_identity_before_checking_device_verification.md rename to .huskies/work/6_archived/256_story_bot_must_verify_other_users_cross_signing_identity_before_checking_device_verification.md index 88ad6df9..a649bb59 100644 --- a/.storkit/work/6_archived/256_story_bot_must_verify_other_users_cross_signing_identity_before_checking_device_verification.md +++ b/.huskies/work/6_archived/256_story_bot_must_verify_other_users_cross_signing_identity_before_checking_device_verification.md @@ -22,7 +22,7 @@ As a Matrix user messaging the bot, I want the bot to correctly recognize my cro ## Test Results - + ### Unit Tests (2 passed, 0 failed) diff --git a/.storkit/work/6_archived/257_story_rename_storkit_to_story_kit_in_header.md b/.huskies/work/6_archived/257_story_rename_storkit_to_story_kit_in_header.md similarity index 100% rename from .storkit/work/6_archived/257_story_rename_storkit_to_story_kit_in_header.md rename to .huskies/work/6_archived/257_story_rename_storkit_to_story_kit_in_header.md diff --git a/.storkit/work/6_archived/258_bug_auto_assign_not_called_after_merge_failure.md b/.huskies/work/6_archived/258_bug_auto_assign_not_called_after_merge_failure.md similarity index 100% rename from .storkit/work/6_archived/258_bug_auto_assign_not_called_after_merge_failure.md rename to .huskies/work/6_archived/258_bug_auto_assign_not_called_after_merge_failure.md diff --git a/.storkit/work/6_archived/259_story_move_story_kit_ignores_into_story_kit_gitignore.md b/.huskies/work/6_archived/259_story_move_story_kit_ignores_into_story_kit_gitignore.md similarity index 56% rename from .storkit/work/6_archived/259_story_move_story_kit_ignores_into_story_kit_gitignore.md rename to .huskies/work/6_archived/259_story_move_story_kit_ignores_into_story_kit_gitignore.md index 38544cbe..7ad2f32e 100644 --- a/.storkit/work/6_archived/259_story_move_story_kit_ignores_into_story_kit_gitignore.md +++ b/.huskies/work/6_archived/259_story_move_story_kit_ignores_into_story_kit_gitignore.md @@ -1,17 +1,17 @@ --- -name: "Move storkit ignores into .story_kit/.gitignore" +name: "Move huskies ignores into .story_kit/.gitignore" --- -# Story 259: Move storkit ignores into .story_kit/.gitignore +# Story 259: Move huskies ignores into .story_kit/.gitignore ## User Story -As a developer using storkit, I want storkit-specific gitignore patterns to live inside .story_kit/.gitignore, so that the host project's root .gitignore stays clean and storkit concerns are self-contained. +As a developer using huskies, I want huskies-specific gitignore patterns to live inside .story_kit/.gitignore, so that the host project's root .gitignore stays clean and huskies concerns are self-contained. ## Acceptance Criteria -- [ ] A .gitignore file exists at .story_kit/.gitignore containing all storkit-specific ignore patterns -- [ ] The root .gitignore no longer contains storkit-specific ignore patterns +- [ ] A .gitignore file exists at .story_kit/.gitignore containing all huskies-specific ignore patterns +- [ ] The root .gitignore no longer contains huskies-specific ignore patterns - [ ] The deterministic project scaffold process creates .story_kit/.gitignore when initialising a new project - [ ] Existing repos continue to work correctly after the change (no previously-ignored files become tracked) diff --git a/.storkit/work/6_archived/25_story_auto_scaffold_story_kit.md b/.huskies/work/6_archived/25_story_auto_scaffold_story_kit.md similarity index 100% rename from .storkit/work/6_archived/25_story_auto_scaffold_story_kit.md rename to .huskies/work/6_archived/25_story_auto_scaffold_story_kit.md diff --git a/.storkit/work/6_archived/261_story_bot_notifications_when_stories_move_between_stages.md b/.huskies/work/6_archived/261_story_bot_notifications_when_stories_move_between_stages.md similarity index 100% rename from .storkit/work/6_archived/261_story_bot_notifications_when_stories_move_between_stages.md rename to .huskies/work/6_archived/261_story_bot_notifications_when_stories_move_between_stages.md diff --git a/.storkit/work/6_archived/262_story_bot_error_notifications_for_story_failures.md b/.huskies/work/6_archived/262_story_bot_error_notifications_for_story_failures.md similarity index 100% rename from .storkit/work/6_archived/262_story_bot_error_notifications_for_story_failures.md rename to .huskies/work/6_archived/262_story_bot_error_notifications_for_story_failures.md diff --git a/.storkit/work/6_archived/263_story_matrix_bot_self_signs_device_keys_at_startup_for_verified_encryption.md b/.huskies/work/6_archived/263_story_matrix_bot_self_signs_device_keys_at_startup_for_verified_encryption.md similarity index 100% rename from .storkit/work/6_archived/263_story_matrix_bot_self_signs_device_keys_at_startup_for_verified_encryption.md rename to .huskies/work/6_archived/263_story_matrix_bot_self_signs_device_keys_at_startup_for_verified_encryption.md diff --git a/.storkit/work/6_archived/264_bug_claude_code_session_id_not_persisted_across_browser_refresh.md b/.huskies/work/6_archived/264_bug_claude_code_session_id_not_persisted_across_browser_refresh.md similarity index 100% rename from .storkit/work/6_archived/264_bug_claude_code_session_id_not_persisted_across_browser_refresh.md rename to .huskies/work/6_archived/264_bug_claude_code_session_id_not_persisted_across_browser_refresh.md diff --git a/.storkit/work/6_archived/265_story_spikes_skip_merge_and_stop_for_human_review.md b/.huskies/work/6_archived/265_story_spikes_skip_merge_and_stop_for_human_review.md similarity index 100% rename from .storkit/work/6_archived/265_story_spikes_skip_merge_and_stop_for_human_review.md rename to .huskies/work/6_archived/265_story_spikes_skip_merge_and_stop_for_human_review.md diff --git a/.storkit/work/6_archived/266_story_matrix_bot_structured_conversation_history.md b/.huskies/work/6_archived/266_story_matrix_bot_structured_conversation_history.md similarity index 100% rename from .storkit/work/6_archived/266_story_matrix_bot_structured_conversation_history.md rename to .huskies/work/6_archived/266_story_matrix_bot_structured_conversation_history.md diff --git a/.storkit/work/6_archived/267_story_mcp_update_story_tool_should_support_front_matter_fields.md b/.huskies/work/6_archived/267_story_mcp_update_story_tool_should_support_front_matter_fields.md similarity index 100% rename from .storkit/work/6_archived/267_story_mcp_update_story_tool_should_support_front_matter_fields.md rename to .huskies/work/6_archived/267_story_mcp_update_story_tool_should_support_front_matter_fields.md diff --git a/.storkit/work/6_archived/268_refactor_upgrade_tokio_tungstenite_to_0_29_0.md b/.huskies/work/6_archived/268_refactor_upgrade_tokio_tungstenite_to_0_29_0.md similarity index 100% rename from .storkit/work/6_archived/268_refactor_upgrade_tokio_tungstenite_to_0_29_0.md rename to .huskies/work/6_archived/268_refactor_upgrade_tokio_tungstenite_to_0_29_0.md diff --git a/.storkit/work/6_archived/269_story_file_references_in_web_ui_chat_input.md b/.huskies/work/6_archived/269_story_file_references_in_web_ui_chat_input.md similarity index 100% rename from .storkit/work/6_archived/269_story_file_references_in_web_ui_chat_input.md rename to .huskies/work/6_archived/269_story_file_references_in_web_ui_chat_input.md diff --git a/.storkit/work/6_archived/26_story_establish_tdd_workflow_and_gates.md b/.huskies/work/6_archived/26_story_establish_tdd_workflow_and_gates.md similarity index 100% rename from .storkit/work/6_archived/26_story_establish_tdd_workflow_and_gates.md rename to .huskies/work/6_archived/26_story_establish_tdd_workflow_and_gates.md diff --git a/.storkit/work/6_archived/270_bug_qa_test_server_overwrites_root_mcp_json_with_wrong_port.md b/.huskies/work/6_archived/270_bug_qa_test_server_overwrites_root_mcp_json_with_wrong_port.md similarity index 100% rename from .storkit/work/6_archived/270_bug_qa_test_server_overwrites_root_mcp_json_with_wrong_port.md rename to .huskies/work/6_archived/270_bug_qa_test_server_overwrites_root_mcp_json_with_wrong_port.md diff --git a/.storkit/work/6_archived/271_story_show_assigned_agent_in_expanded_work_item_view.md b/.huskies/work/6_archived/271_story_show_assigned_agent_in_expanded_work_item_view.md similarity index 100% rename from .storkit/work/6_archived/271_story_show_assigned_agent_in_expanded_work_item_view.md rename to .huskies/work/6_archived/271_story_show_assigned_agent_in_expanded_work_item_view.md diff --git a/.storkit/work/6_archived/272_story_clear_merge_error_front_matter_when_story_leaves_merge_stage.md b/.huskies/work/6_archived/272_story_clear_merge_error_front_matter_when_story_leaves_merge_stage.md similarity index 100% rename from .storkit/work/6_archived/272_story_clear_merge_error_front_matter_when_story_leaves_merge_stage.md rename to .huskies/work/6_archived/272_story_clear_merge_error_front_matter_when_story_leaves_merge_stage.md diff --git a/.storkit/work/6_archived/273_story_matrix_bot_sends_typing_indicator_while_waiting_for_claude_response.md b/.huskies/work/6_archived/273_story_matrix_bot_sends_typing_indicator_while_waiting_for_claude_response.md similarity index 100% rename from .storkit/work/6_archived/273_story_matrix_bot_sends_typing_indicator_while_waiting_for_claude_response.md rename to .huskies/work/6_archived/273_story_matrix_bot_sends_typing_indicator_while_waiting_for_claude_response.md diff --git a/.storkit/work/6_archived/274_story_mcp_pipeline_status_tool_with_agent_assignments.md b/.huskies/work/6_archived/274_story_mcp_pipeline_status_tool_with_agent_assignments.md similarity index 100% rename from .storkit/work/6_archived/274_story_mcp_pipeline_status_tool_with_agent_assignments.md rename to .huskies/work/6_archived/274_story_mcp_pipeline_status_tool_with_agent_assignments.md diff --git a/.storkit/work/6_archived/275_story_matrix_bot_surfaces_claude_code_permission_prompts_to_chat.md b/.huskies/work/6_archived/275_story_matrix_bot_surfaces_claude_code_permission_prompts_to_chat.md similarity index 100% rename from .storkit/work/6_archived/275_story_matrix_bot_surfaces_claude_code_permission_prompts_to_chat.md rename to .huskies/work/6_archived/275_story_matrix_bot_surfaces_claude_code_permission_prompts_to_chat.md diff --git a/.storkit/work/6_archived/276_story_detect_and_log_when_root_mcp_json_port_is_modified.md b/.huskies/work/6_archived/276_story_detect_and_log_when_root_mcp_json_port_is_modified.md similarity index 100% rename from .storkit/work/6_archived/276_story_detect_and_log_when_root_mcp_json_port_is_modified.md rename to .huskies/work/6_archived/276_story_detect_and_log_when_root_mcp_json_port_is_modified.md diff --git a/.storkit/work/6_archived/277_story_matrix_bot_uses_its_configured_name_instead_of_claude.md b/.huskies/work/6_archived/277_story_matrix_bot_uses_its_configured_name_instead_of_claude.md similarity index 100% rename from .storkit/work/6_archived/277_story_matrix_bot_uses_its_configured_name_instead_of_claude.md rename to .huskies/work/6_archived/277_story_matrix_bot_uses_its_configured_name_instead_of_claude.md diff --git a/.storkit/work/6_archived/278_story_auto_assign_agents_to_pipeline_items_on_server_startup.md b/.huskies/work/6_archived/278_story_auto_assign_agents_to_pipeline_items_on_server_startup.md similarity index 100% rename from .storkit/work/6_archived/278_story_auto_assign_agents_to_pipeline_items_on_server_startup.md rename to .huskies/work/6_archived/278_story_auto_assign_agents_to_pipeline_items_on_server_startup.md diff --git a/.storkit/work/6_archived/279_story_auto_assign_should_respect_agent_stage_when_front_matter_specifies_agent.md b/.huskies/work/6_archived/279_story_auto_assign_should_respect_agent_stage_when_front_matter_specifies_agent.md similarity index 100% rename from .storkit/work/6_archived/279_story_auto_assign_should_respect_agent_stage_when_front_matter_specifies_agent.md rename to .huskies/work/6_archived/279_story_auto_assign_should_respect_agent_stage_when_front_matter_specifies_agent.md diff --git a/.storkit/work/6_archived/27_story_protect_tests_and_coverage.md b/.huskies/work/6_archived/27_story_protect_tests_and_coverage.md similarity index 100% rename from .storkit/work/6_archived/27_story_protect_tests_and_coverage.md rename to .huskies/work/6_archived/27_story_protect_tests_and_coverage.md diff --git a/.storkit/work/6_archived/281_story_matrix_bot_announces_itself_when_it_comes_online.md b/.huskies/work/6_archived/281_story_matrix_bot_announces_itself_when_it_comes_online.md similarity index 100% rename from .storkit/work/6_archived/281_story_matrix_bot_announces_itself_when_it_comes_online.md rename to .huskies/work/6_archived/281_story_matrix_bot_announces_itself_when_it_comes_online.md diff --git a/.storkit/work/6_archived/282_story_matrix_bot_ambient_mode_toggle_via_chat_command.md b/.huskies/work/6_archived/282_story_matrix_bot_ambient_mode_toggle_via_chat_command.md similarity index 100% rename from .storkit/work/6_archived/282_story_matrix_bot_ambient_mode_toggle_via_chat_command.md rename to .huskies/work/6_archived/282_story_matrix_bot_ambient_mode_toggle_via_chat_command.md diff --git a/.storkit/work/6_archived/283_bug_pipeline_does_not_check_manual_qa_flag_before_advancing_from_qa_to_merge.md b/.huskies/work/6_archived/283_bug_pipeline_does_not_check_manual_qa_flag_before_advancing_from_qa_to_merge.md similarity index 100% rename from .storkit/work/6_archived/283_bug_pipeline_does_not_check_manual_qa_flag_before_advancing_from_qa_to_merge.md rename to .huskies/work/6_archived/283_bug_pipeline_does_not_check_manual_qa_flag_before_advancing_from_qa_to_merge.md diff --git a/.storkit/work/6_archived/284_story_matrix_bot_status_command_shows_pipeline_and_agent_availability.md b/.huskies/work/6_archived/284_story_matrix_bot_status_command_shows_pipeline_and_agent_availability.md similarity index 100% rename from .storkit/work/6_archived/284_story_matrix_bot_status_command_shows_pipeline_and_agent_availability.md rename to .huskies/work/6_archived/284_story_matrix_bot_status_command_shows_pipeline_and_agent_availability.md diff --git a/.storkit/work/6_archived/285_story_matrix_bot_help_command_lists_available_bot_commands.md b/.huskies/work/6_archived/285_story_matrix_bot_help_command_lists_available_bot_commands.md similarity index 100% rename from .storkit/work/6_archived/285_story_matrix_bot_help_command_lists_available_bot_commands.md rename to .huskies/work/6_archived/285_story_matrix_bot_help_command_lists_available_bot_commands.md diff --git a/.storkit/work/6_archived/286_story_server_self_rebuild_and_restart_via_mcp_tool.md b/.huskies/work/6_archived/286_story_server_self_rebuild_and_restart_via_mcp_tool.md similarity index 100% rename from .storkit/work/6_archived/286_story_server_self_rebuild_and_restart_via_mcp_tool.md rename to .huskies/work/6_archived/286_story_server_self_rebuild_and_restart_via_mcp_tool.md diff --git a/.storkit/work/6_archived/287_story_rename_upcoming_pipeline_stage_to_backlog.md b/.huskies/work/6_archived/287_story_rename_upcoming_pipeline_stage_to_backlog.md similarity index 100% rename from .storkit/work/6_archived/287_story_rename_upcoming_pipeline_stage_to_backlog.md rename to .huskies/work/6_archived/287_story_rename_upcoming_pipeline_stage_to_backlog.md diff --git a/.storkit/work/6_archived/288_bug_ambient_mode_state_lost_on_server_restart.md b/.huskies/work/6_archived/288_bug_ambient_mode_state_lost_on_server_restart.md similarity index 100% rename from .storkit/work/6_archived/288_bug_ambient_mode_state_lost_on_server_restart.md rename to .huskies/work/6_archived/288_bug_ambient_mode_state_lost_on_server_restart.md diff --git a/.storkit/work/6_archived/289_bug_rebuild_and_restart_mcp_tool_does_not_rebuild.md b/.huskies/work/6_archived/289_bug_rebuild_and_restart_mcp_tool_does_not_rebuild.md similarity index 100% rename from .storkit/work/6_archived/289_bug_rebuild_and_restart_mcp_tool_does_not_rebuild.md rename to .huskies/work/6_archived/289_bug_rebuild_and_restart_mcp_tool_does_not_rebuild.md diff --git a/.storkit/work/6_archived/28_story_ui_show_test_todos.md b/.huskies/work/6_archived/28_story_ui_show_test_todos.md similarity index 100% rename from .storkit/work/6_archived/28_story_ui_show_test_todos.md rename to .huskies/work/6_archived/28_story_ui_show_test_todos.md diff --git a/.storkit/work/6_archived/290_story_show_agent_output_stream_in_expanded_work_item_detail_panel.md b/.huskies/work/6_archived/290_story_show_agent_output_stream_in_expanded_work_item_detail_panel.md similarity index 100% rename from .storkit/work/6_archived/290_story_show_agent_output_stream_in_expanded_work_item_detail_panel.md rename to .huskies/work/6_archived/290_story_show_agent_output_stream_in_expanded_work_item_detail_panel.md diff --git a/.storkit/work/6_archived/291_story_show_test_results_in_work_item_detail_panel.md b/.huskies/work/6_archived/291_story_show_test_results_in_work_item_detail_panel.md similarity index 100% rename from .storkit/work/6_archived/291_story_show_test_results_in_work_item_detail_panel.md rename to .huskies/work/6_archived/291_story_show_test_results_in_work_item_detail_panel.md diff --git a/.storkit/work/6_archived/292_story_show_server_logs_in_web_ui.md b/.huskies/work/6_archived/292_story_show_server_logs_in_web_ui.md similarity index 100% rename from .storkit/work/6_archived/292_story_show_server_logs_in_web_ui.md rename to .huskies/work/6_archived/292_story_show_server_logs_in_web_ui.md diff --git a/.storkit/work/6_archived/293_story_register_all_bot_commands_in_the_command_registry.md b/.huskies/work/6_archived/293_story_register_all_bot_commands_in_the_command_registry.md similarity index 100% rename from .storkit/work/6_archived/293_story_register_all_bot_commands_in_the_command_registry.md rename to .huskies/work/6_archived/293_story_register_all_bot_commands_in_the_command_registry.md diff --git a/.huskies/work/6_archived/294_story_rename_app_title_from_story_kit_to_storkit.md b/.huskies/work/6_archived/294_story_rename_app_title_from_story_kit_to_storkit.md new file mode 100644 index 00000000..a348b7aa --- /dev/null +++ b/.huskies/work/6_archived/294_story_rename_app_title_from_story_kit_to_storkit.md @@ -0,0 +1,19 @@ +--- +name: "Rename app title from Story Kit to Huskies" +review_hold: true +--- + +# Story 294: Rename app title from Story Kit to Huskies + +## User Story + +As a user, I want the application title to say "Huskies" instead of "Story Kit", so that the branding reflects the new name. + +## Acceptance Criteria + +- [ ] The top title in the web UI header displays "Huskies" instead of "Story Kit" +- [ ] Any other visible references to "Story Kit" in the UI are updated to "Huskies" + +## Out of Scope + +- TBD diff --git a/.storkit/work/6_archived/295_bug_stories_stuck_in_qa_when_qa_agent_is_busy.md b/.huskies/work/6_archived/295_bug_stories_stuck_in_qa_when_qa_agent_is_busy.md similarity index 100% rename from .storkit/work/6_archived/295_bug_stories_stuck_in_qa_when_qa_agent_is_busy.md rename to .huskies/work/6_archived/295_bug_stories_stuck_in_qa_when_qa_agent_is_busy.md diff --git a/.storkit/work/6_archived/296_story_track_per_agent_token_usage_for_cost_visibility_and_optimisation.md b/.huskies/work/6_archived/296_story_track_per_agent_token_usage_for_cost_visibility_and_optimisation.md similarity index 100% rename from .storkit/work/6_archived/296_story_track_per_agent_token_usage_for_cost_visibility_and_optimisation.md rename to .huskies/work/6_archived/296_story_track_per_agent_token_usage_for_cost_visibility_and_optimisation.md diff --git a/.storkit/work/6_archived/297_story_improve_bot_status_command_formatting.md b/.huskies/work/6_archived/297_story_improve_bot_status_command_formatting.md similarity index 100% rename from .storkit/work/6_archived/297_story_improve_bot_status_command_formatting.md rename to .huskies/work/6_archived/297_story_improve_bot_status_command_formatting.md diff --git a/.storkit/work/6_archived/298_story_bot_htop_command_with_live_updating_process_dashboard.md b/.huskies/work/6_archived/298_story_bot_htop_command_with_live_updating_process_dashboard.md similarity index 100% rename from .storkit/work/6_archived/298_story_bot_htop_command_with_live_updating_process_dashboard.md rename to .huskies/work/6_archived/298_story_bot_htop_command_with_live_updating_process_dashboard.md diff --git a/.storkit/work/6_archived/299_story_bot_git_status_command_shows_working_tree_and_branch_info.md b/.huskies/work/6_archived/299_story_bot_git_status_command_shows_working_tree_and_branch_info.md similarity index 100% rename from .storkit/work/6_archived/299_story_bot_git_status_command_shows_working_tree_and_branch_info.md rename to .huskies/work/6_archived/299_story_bot_git_status_command_shows_working_tree_and_branch_info.md diff --git a/.storkit/work/6_archived/29_story_backfill_tests_high_coverage.md b/.huskies/work/6_archived/29_story_backfill_tests_high_coverage.md similarity index 100% rename from .storkit/work/6_archived/29_story_backfill_tests_high_coverage.md rename to .huskies/work/6_archived/29_story_backfill_tests_high_coverage.md diff --git a/.storkit/work/6_archived/2_bug_agent_panel_expand_does_nothing.md b/.huskies/work/6_archived/2_bug_agent_panel_expand_does_nothing.md similarity index 100% rename from .storkit/work/6_archived/2_bug_agent_panel_expand_does_nothing.md rename to .huskies/work/6_archived/2_bug_agent_panel_expand_does_nothing.md diff --git a/.storkit/work/6_archived/300_story_show_token_cost_badge_on_pipeline_board_work_items.md b/.huskies/work/6_archived/300_story_show_token_cost_badge_on_pipeline_board_work_items.md similarity index 100% rename from .storkit/work/6_archived/300_story_show_token_cost_badge_on_pipeline_board_work_items.md rename to .huskies/work/6_archived/300_story_show_token_cost_badge_on_pipeline_board_work_items.md diff --git a/.storkit/work/6_archived/301_story_dedicated_token_usage_page_in_web_ui.md b/.huskies/work/6_archived/301_story_dedicated_token_usage_page_in_web_ui.md similarity index 100% rename from .storkit/work/6_archived/301_story_dedicated_token_usage_page_in_web_ui.md rename to .huskies/work/6_archived/301_story_dedicated_token_usage_page_in_web_ui.md diff --git a/.storkit/work/6_archived/302_story_bot_cost_command_shows_total_and_per_story_token_spend.md b/.huskies/work/6_archived/302_story_bot_cost_command_shows_total_and_per_story_token_spend.md similarity index 100% rename from .storkit/work/6_archived/302_story_bot_cost_command_shows_total_and_per_story_token_spend.md rename to .huskies/work/6_archived/302_story_bot_cost_command_shows_total_and_per_story_token_spend.md diff --git a/.storkit/work/6_archived/303_story_bot_cost_command_with_story_filter_for_detailed_breakdown.md b/.huskies/work/6_archived/303_story_bot_cost_command_with_story_filter_for_detailed_breakdown.md similarity index 100% rename from .storkit/work/6_archived/303_story_bot_cost_command_with_story_filter_for_detailed_breakdown.md rename to .huskies/work/6_archived/303_story_bot_cost_command_with_story_filter_for_detailed_breakdown.md diff --git a/.storkit/work/6_archived/304_story_mcp_tool_to_move_stories_between_pipeline_stages.md b/.huskies/work/6_archived/304_story_mcp_tool_to_move_stories_between_pipeline_stages.md similarity index 100% rename from .storkit/work/6_archived/304_story_mcp_tool_to_move_stories_between_pipeline_stages.md rename to .huskies/work/6_archived/304_story_mcp_tool_to_move_stories_between_pipeline_stages.md diff --git a/.storkit/work/6_archived/305_story_bot_show_command_displays_story_text_in_chat.md b/.huskies/work/6_archived/305_story_bot_show_command_displays_story_text_in_chat.md similarity index 100% rename from .storkit/work/6_archived/305_story_bot_show_command_displays_story_text_in_chat.md rename to .huskies/work/6_archived/305_story_bot_show_command_displays_story_text_in_chat.md diff --git a/.storkit/work/6_archived/306_story_replace_manual_qa_boolean_with_configurable_qa_mode_field.md b/.huskies/work/6_archived/306_story_replace_manual_qa_boolean_with_configurable_qa_mode_field.md similarity index 100% rename from .storkit/work/6_archived/306_story_replace_manual_qa_boolean_with_configurable_qa_mode_field.md rename to .huskies/work/6_archived/306_story_replace_manual_qa_boolean_with_configurable_qa_mode_field.md diff --git a/.storkit/work/6_archived/307_story_configurable_coder_pool_size_and_default_model_in_project_toml.md b/.huskies/work/6_archived/307_story_configurable_coder_pool_size_and_default_model_in_project_toml.md similarity index 100% rename from .storkit/work/6_archived/307_story_configurable_coder_pool_size_and_default_model_in_project_toml.md rename to .huskies/work/6_archived/307_story_configurable_coder_pool_size_and_default_model_in_project_toml.md diff --git a/.storkit/work/6_archived/309_story_show_token_cost_breakdown_in_expanded_work_item_detail_panel.md b/.huskies/work/6_archived/309_story_show_token_cost_breakdown_in_expanded_work_item_detail_panel.md similarity index 100% rename from .storkit/work/6_archived/309_story_show_token_cost_breakdown_in_expanded_work_item_detail_panel.md rename to .huskies/work/6_archived/309_story_show_token_cost_breakdown_in_expanded_work_item_detail_panel.md diff --git a/.storkit/work/6_archived/30_story_worktree_agent_orchestration.md b/.huskies/work/6_archived/30_story_worktree_agent_orchestration.md similarity index 100% rename from .storkit/work/6_archived/30_story_worktree_agent_orchestration.md rename to .huskies/work/6_archived/30_story_worktree_agent_orchestration.md diff --git a/.storkit/work/6_archived/310_story_bot_delete_command_removes_a_story_from_the_pipeline.md b/.huskies/work/6_archived/310_story_bot_delete_command_removes_a_story_from_the_pipeline.md similarity index 100% rename from .storkit/work/6_archived/310_story_bot_delete_command_removes_a_story_from_the_pipeline.md rename to .huskies/work/6_archived/310_story_bot_delete_command_removes_a_story_from_the_pipeline.md diff --git a/.storkit/work/6_archived/311_story_server_enforced_retry_limits_for_failed_merge_and_empty_diff_stories.md b/.huskies/work/6_archived/311_story_server_enforced_retry_limits_for_failed_merge_and_empty_diff_stories.md similarity index 100% rename from .storkit/work/6_archived/311_story_server_enforced_retry_limits_for_failed_merge_and_empty_diff_stories.md rename to .huskies/work/6_archived/311_story_server_enforced_retry_limits_for_failed_merge_and_empty_diff_stories.md diff --git a/.storkit/work/6_archived/312_bug_auto_assign_assigns_mergemaster_to_coding_stage_stories.md b/.huskies/work/6_archived/312_bug_auto_assign_assigns_mergemaster_to_coding_stage_stories.md similarity index 100% rename from .storkit/work/6_archived/312_bug_auto_assign_assigns_mergemaster_to_coding_stage_stories.md rename to .huskies/work/6_archived/312_bug_auto_assign_assigns_mergemaster_to_coding_stage_stories.md diff --git a/.storkit/work/6_archived/313_story_improve_htop_output_formatting_for_mobile_matrix_clients.md b/.huskies/work/6_archived/313_story_improve_htop_output_formatting_for_mobile_matrix_clients.md similarity index 100% rename from .storkit/work/6_archived/313_story_improve_htop_output_formatting_for_mobile_matrix_clients.md rename to .huskies/work/6_archived/313_story_improve_htop_output_formatting_for_mobile_matrix_clients.md diff --git a/.storkit/work/6_archived/314_story_show_token_cost_per_story_in_bot_status_command_output.md b/.huskies/work/6_archived/314_story_show_token_cost_per_story_in_bot_status_command_output.md similarity index 100% rename from .storkit/work/6_archived/314_story_show_token_cost_per_story_in_bot_status_command_output.md rename to .huskies/work/6_archived/314_story_show_token_cost_per_story_in_bot_status_command_output.md diff --git a/.huskies/work/6_archived/315_story_rename_binary_and_all_references_from_story_kit_to_storkit.md b/.huskies/work/6_archived/315_story_rename_binary_and_all_references_from_story_kit_to_storkit.md new file mode 100644 index 00000000..aeeaad89 --- /dev/null +++ b/.huskies/work/6_archived/315_story_rename_binary_and_all_references_from_story_kit_to_storkit.md @@ -0,0 +1,28 @@ +--- +name: "Rename binary and all references from huskies to huskies" +agent: coder-opus +--- + +# Story 315: Rename binary and all references from huskies to huskies + +## User Story + +As a project owner, I want the binary, crate name, package name, and all code/config references renamed from huskies/story_kit to huskies, so that the branding is consistent throughout the project. + +## Acceptance Criteria + +- [ ] Binary name changed from huskies to huskies in Cargo.toml +- [ ] Crate/package name changed from huskies/story_kit to huskies throughout Cargo.toml files +- [ ] All code references to story_kit (module names, paths, env vars like CARGO_MANIFEST_DIR) updated +- [ ] Config directory .story_kit renamed to .huskies +- [ ] All server code references to .story_kit paths updated +- [ ] Git commit messages prefix changed from 'huskies:' to 'huskies:' +- [ ] Frontend references updated (if any) +- [ ] script/* files updated to reference the new binary name +- [ ] Release script updated for new binary name +- [ ] MCP server name updated from huskies to huskies +- [ ] CLAUDE.md and README references updated + +## Out of Scope + +- TBD diff --git a/.storkit/work/6_archived/316_refactor_abstract_bot_transport_layer_for_multi_platform_support.md b/.huskies/work/6_archived/316_refactor_abstract_bot_transport_layer_for_multi_platform_support.md similarity index 100% rename from .storkit/work/6_archived/316_refactor_abstract_bot_transport_layer_for_multi_platform_support.md rename to .huskies/work/6_archived/316_refactor_abstract_bot_transport_layer_for_multi_platform_support.md diff --git a/.storkit/work/6_archived/317_refactor_split_pool_rs_into_pipeline_auto_assign_and_agent_management_modules.md b/.huskies/work/6_archived/317_refactor_split_pool_rs_into_pipeline_auto_assign_and_agent_management_modules.md similarity index 100% rename from .storkit/work/6_archived/317_refactor_split_pool_rs_into_pipeline_auto_assign_and_agent_management_modules.md rename to .huskies/work/6_archived/317_refactor_split_pool_rs_into_pipeline_auto_assign_and_agent_management_modules.md diff --git a/.storkit/work/6_archived/318_refactor_split_mcp_rs_into_domain_specific_tool_modules.md b/.huskies/work/6_archived/318_refactor_split_mcp_rs_into_domain_specific_tool_modules.md similarity index 100% rename from .storkit/work/6_archived/318_refactor_split_mcp_rs_into_domain_specific_tool_modules.md rename to .huskies/work/6_archived/318_refactor_split_mcp_rs_into_domain_specific_tool_modules.md diff --git a/.storkit/work/6_archived/319_refactor_split_workflow_rs_into_story_bug_and_test_result_modules.md b/.huskies/work/6_archived/319_refactor_split_workflow_rs_into_story_bug_and_test_result_modules.md similarity index 100% rename from .storkit/work/6_archived/319_refactor_split_workflow_rs_into_story_bug_and_test_result_modules.md rename to .huskies/work/6_archived/319_refactor_split_workflow_rs_into_story_bug_and_test_result_modules.md diff --git a/.storkit/work/6_archived/31_story_view_upcoming_stories.md b/.huskies/work/6_archived/31_story_view_upcoming_stories.md similarity index 100% rename from .storkit/work/6_archived/31_story_view_upcoming_stories.md rename to .huskies/work/6_archived/31_story_view_upcoming_stories.md diff --git a/.storkit/work/6_archived/320_story_whatsapp_business_api_integration_for_bot_commands.md b/.huskies/work/6_archived/320_story_whatsapp_business_api_integration_for_bot_commands.md similarity index 100% rename from .storkit/work/6_archived/320_story_whatsapp_business_api_integration_for_bot_commands.md rename to .huskies/work/6_archived/320_story_whatsapp_business_api_integration_for_bot_commands.md diff --git a/.storkit/work/6_archived/321_story_whatsapp_htop_adaptation_for_no_edit_platforms.md b/.huskies/work/6_archived/321_story_whatsapp_htop_adaptation_for_no_edit_platforms.md similarity index 100% rename from .storkit/work/6_archived/321_story_whatsapp_htop_adaptation_for_no_edit_platforms.md rename to .huskies/work/6_archived/321_story_whatsapp_htop_adaptation_for_no_edit_platforms.md diff --git a/.storkit/work/6_archived/322_story_whatsapp_24_hour_messaging_window_and_template_support.md b/.huskies/work/6_archived/322_story_whatsapp_24_hour_messaging_window_and_template_support.md similarity index 100% rename from .storkit/work/6_archived/322_story_whatsapp_24_hour_messaging_window_and_template_support.md rename to .huskies/work/6_archived/322_story_whatsapp_24_hour_messaging_window_and_template_support.md diff --git a/.storkit/work/6_archived/323_story_whatsapp_llm_passthrough_for_conversational_queries.md b/.huskies/work/6_archived/323_story_whatsapp_llm_passthrough_for_conversational_queries.md similarity index 100% rename from .storkit/work/6_archived/323_story_whatsapp_llm_passthrough_for_conversational_queries.md rename to .huskies/work/6_archived/323_story_whatsapp_llm_passthrough_for_conversational_queries.md diff --git a/.storkit/work/6_archived/324_story_slack_bot_integration_for_bot_commands.md b/.huskies/work/6_archived/324_story_slack_bot_integration_for_bot_commands.md similarity index 100% rename from .storkit/work/6_archived/324_story_slack_bot_integration_for_bot_commands.md rename to .huskies/work/6_archived/324_story_slack_bot_integration_for_bot_commands.md diff --git a/.storkit/work/6_archived/325_story_slack_llm_passthrough_for_conversational_queries.md b/.huskies/work/6_archived/325_story_slack_llm_passthrough_for_conversational_queries.md similarity index 100% rename from .storkit/work/6_archived/325_story_slack_llm_passthrough_for_conversational_queries.md rename to .huskies/work/6_archived/325_story_slack_llm_passthrough_for_conversational_queries.md diff --git a/.storkit/work/6_archived/326_story_slack_slash_commands_for_pipeline_management.md b/.huskies/work/6_archived/326_story_slack_slash_commands_for_pipeline_management.md similarity index 73% rename from .storkit/work/6_archived/326_story_slack_slash_commands_for_pipeline_management.md rename to .huskies/work/6_archived/326_story_slack_slash_commands_for_pipeline_management.md index 4aa12140..f2cd17b3 100644 --- a/.storkit/work/6_archived/326_story_slack_slash_commands_for_pipeline_management.md +++ b/.huskies/work/6_archived/326_story_slack_slash_commands_for_pipeline_management.md @@ -6,12 +6,12 @@ name: "Slack slash commands for pipeline management" ## User Story -As a Slack user, I want to use slash commands like /storkit-status and /storkit-cost as an alternative to mentioning the bot, so that I can quickly access pipeline info with minimal typing. +As a Slack user, I want to use slash commands like /huskies-status and /huskies-cost as an alternative to mentioning the bot, so that I can quickly access pipeline info with minimal typing. ## Acceptance Criteria - [ ] Slash command endpoint at /webhook/slack/command handles Slack slash command payloads -- [ ] Supports /storkit-status, /storkit-cost, /storkit-show, /storkit-git, /storkit-htop +- [ ] Supports /huskies-status, /huskies-cost, /huskies-show, /huskies-git, /huskies-htop - [ ] Slash command responses are ephemeral by default (only visible to the caller) - [ ] Slash commands documented in setup guide with Slack app configuration steps - [ ] Registered in the command registry so they share handlers with the mention-based commands diff --git a/.storkit/work/6_archived/327_story_bot_overview_command_shows_implementation_summary_for_a_story.md b/.huskies/work/6_archived/327_story_bot_overview_command_shows_implementation_summary_for_a_story.md similarity index 100% rename from .storkit/work/6_archived/327_story_bot_overview_command_shows_implementation_summary_for_a_story.md rename to .huskies/work/6_archived/327_story_bot_overview_command_shows_implementation_summary_for_a_story.md diff --git a/.storkit/work/6_archived/328_refactor_split_commands_rs_into_individual_command_handler_modules.md b/.huskies/work/6_archived/328_refactor_split_commands_rs_into_individual_command_handler_modules.md similarity index 100% rename from .storkit/work/6_archived/328_refactor_split_commands_rs_into_individual_command_handler_modules.md rename to .huskies/work/6_archived/328_refactor_split_commands_rs_into_individual_command_handler_modules.md diff --git a/.storkit/work/6_archived/329_spike_evaluate_docker_orbstack_for_agent_isolation_and_resource_limiting.md b/.huskies/work/6_archived/329_spike_evaluate_docker_orbstack_for_agent_isolation_and_resource_limiting.md similarity index 91% rename from .storkit/work/6_archived/329_spike_evaluate_docker_orbstack_for_agent_isolation_and_resource_limiting.md rename to .huskies/work/6_archived/329_spike_evaluate_docker_orbstack_for_agent_isolation_and_resource_limiting.md index fb771514..1ece0461 100644 --- a/.storkit/work/6_archived/329_spike_evaluate_docker_orbstack_for_agent_isolation_and_resource_limiting.md +++ b/.huskies/work/6_archived/329_spike_evaluate_docker_orbstack_for_agent_isolation_and_resource_limiting.md @@ -7,23 +7,23 @@ agent: "coder-opus" ## Question -Investigate running the entire storkit system (server, Matrix bot, agents, web UI) inside a single Docker container, using OrbStack as the macOS runtime for better performance. The goal is to isolate storkit from the host machine — not to isolate agents from each other. +Investigate running the entire huskies system (server, Matrix bot, agents, web UI) inside a single Docker container, using OrbStack as the macOS runtime for better performance. The goal is to isolate huskies from the host machine — not to isolate agents from each other. -**Important context:** Storkit developing itself is the dogfood edge case. The primary use case is storkit managing agents that develop *other* projects, driven by multiple users in chat rooms (Matrix, WhatsApp, Slack). Isolation must account for untrusted codebases, multi-user command surfaces, and running against arbitrary repos — not just the single-developer self-hosted setup. +**Important context:** Huskies developing itself is the dogfood edge case. The primary use case is huskies managing agents that develop *other* projects, driven by multiple users in chat rooms (Matrix, WhatsApp, Slack). Isolation must account for untrusted codebases, multi-user command surfaces, and running against arbitrary repos — not just the single-developer self-hosted setup. -Currently storkit runs as bare processes on the host with full filesystem and network access. A single container would provide: +Currently huskies runs as bare processes on the host with full filesystem and network access. A single container would provide: -1. **Host isolation** — storkit can't touch anything outside the container +1. **Host isolation** — huskies can't touch anything outside the container 2. **Clean install/uninstall** — `docker run` to start, `docker rm` to remove 3. **Reproducible environment** — same container works on any machine -4. **Distributable product** — `docker pull storkit` for new users +4. **Distributable product** — `docker pull huskies` for new users 5. **Resource limits** — cap total CPU/memory for the whole system ## Architecture ``` Docker Container (single) -├── storkit server +├── huskies server │ ├── Matrix bot │ ├── WhatsApp webhook │ ├── Slack webhook @@ -52,7 +52,7 @@ A proof-of-concept Dockerfile, docker-compose.yml, and a short write-up with fin ## Hypothesis -A single Docker container running the entire storkit stack (server + agents + toolchain) on OrbStack will provide acceptable performance for the primary use case (developing other projects) while giving us host isolation, resource limits, and a distributable product. OrbStack's VirtioFS should make bind-mounted filesystem performance close to native. +A single Docker container running the entire huskies stack (server + agents + toolchain) on OrbStack will provide acceptable performance for the primary use case (developing other projects) while giving us host isolation, resource limits, and a distributable product. OrbStack's VirtioFS should make bind-mounted filesystem performance close to native. ## Timebox @@ -60,7 +60,7 @@ A single Docker container running the entire storkit stack (server + agents + to ## Investigation Plan -1. Audit storkit's runtime dependencies (Rust toolchain, Node.js, Claude Code CLI, cargo-nextest, git) +1. Audit huskies's runtime dependencies (Rust toolchain, Node.js, Claude Code CLI, cargo-nextest, git) 2. Determine where Claude Code stores session state (~/.claude) 3. Analyze how rebuild_and_restart works (exec() replacement) and whether it's container-compatible 4. Draft a multi-stage Dockerfile and docker-compose.yml @@ -76,12 +76,12 @@ A single Docker container running the entire storkit stack (server + agents + to The image requires these runtime components: - **Rust 1.90+ toolchain** (~1.5 GB) — needed at runtime for `rebuild_and_restart` and agent-driven `cargo clippy`, `cargo test`, etc. - **Node.js 22.x** (~100 MB) — needed at runtime for Claude Code CLI (npm global package) -- **Claude Code CLI** (`@anthropic-ai/claude-code`) — npm global, spawned by storkit via PTY +- **Claude Code CLI** (`@anthropic-ai/claude-code`) — npm global, spawned by huskies via PTY - **cargo-nextest** — pre-built binary, used by acceptance gates - **git** — used extensively by agents and worktree management - **System libs:** libssl3, ca-certificates -The build stage compiles the storkit binary with embedded frontend assets (build.rs runs `npm run build`). The runtime stage is based on `debian:bookworm-slim` but still needs Rust + Node because agents use them at runtime. +The build stage compiles the huskies binary with embedded frontend assets (build.rs runs `npm run build`). The runtime stage is based on `debian:bookworm-slim` but still needs Rust + Node because agents use them at runtime. **Total estimated image size:** ~3-4 GB (dominated by the Rust toolchain). This is large but acceptable for a development tool that runs locally. @@ -119,7 +119,7 @@ Port mapping: `3001:3001` in docker-compose.yml. Users access the web UI at `htt ### 5. API key handling -**Simple.** Pass `ANTHROPIC_API_KEY` as an environment variable via docker-compose.yml. The storkit server already reads it from the environment. Claude Code also reads `ANTHROPIC_API_KEY` from the environment. +**Simple.** Pass `ANTHROPIC_API_KEY` as an environment variable via docker-compose.yml. The huskies server already reads it from the environment. Claude Code also reads `ANTHROPIC_API_KEY` from the environment. ### 6. Git operations on bind-mounted repos @@ -159,14 +159,14 @@ Inside a container, `exec()` works fine — it replaces the PID 1 process. Howev **The Dockerfile handles this** by copying the full source tree into `/app` in the runtime stage and including the Rust toolchain. -**Future improvement:** For the storkit-developing-itself case, mount the source tree as a volume at `/app` so code changes on the host are immediately available for rebuild. For the primary use case (developing other projects), the baked-in source is fine — the server doesn't change. +**Future improvement:** For the huskies-developing-itself case, mount the source tree as a volume at `/app` so code changes on the host are immediately available for rebuild. For the primary use case (developing other projects), the baked-in source is fine — the server doesn't change. ### 10. Multi-user / untrusted codebase considerations The single-container model provides **host isolation** but no **agent-to-agent isolation**: - All agents share the same filesystem, network, and process namespace -- A malicious codebase could interfere with other agents or the storkit server itself -- This is acceptable as a first step since the primary threat model is "storkit shouldn't wreck the host" +- A malicious codebase could interfere with other agents or the huskies server itself +- This is acceptable as a first step since the primary threat model is "huskies shouldn't wreck the host" For true multi-tenant isolation (multiple untrusted projects), a future architecture could: - Run one container per project (each with its own bind mount) @@ -177,8 +177,8 @@ For true multi-tenant isolation (multiple untrusted projects), a future architec The single-container approach enables simple distribution: ``` -docker pull ghcr.io/crashlabs/storkit:latest -docker run -e ANTHROPIC_API_KEY=sk-ant-... -v /my/project:/workspace -p 3001:3001 storkit +docker pull ghcr.io/crashlabs/huskies:latest +docker run -e ANTHROPIC_API_KEY=sk-ant-... -v /my/project:/workspace -p 3001:3001 huskies ``` This is a massive UX improvement over "install Rust, install Node, install Claude Code, clone the repo, cargo build, etc." @@ -201,9 +201,9 @@ This is a massive UX improvement over "install Rust, install Node, install Claud 3. **Story: Git identity in container** — Configure git user.name/email inside the container (from env vars or mounted .gitconfig). -4. **Story: Per-project container isolation** — For multi-tenant deployments, run one storkit container per project with tighter security (read-only root, seccomp, no-new-privileges). +4. **Story: Per-project container isolation** — For multi-tenant deployments, run one huskies container per project with tighter security (read-only root, seccomp, no-new-privileges). -5. **Story: Health endpoint** — Add a `/health` HTTP endpoint to the storkit server for the Docker healthcheck. +5. **Story: Health endpoint** — Add a `/health` HTTP endpoint to the huskies server for the Docker healthcheck. ### Risks and open questions: diff --git a/.storkit/work/6_archived/32_story_multi_instance_worktree_support.md b/.huskies/work/6_archived/32_story_multi_instance_worktree_support.md similarity index 100% rename from .storkit/work/6_archived/32_story_multi_instance_worktree_support.md rename to .huskies/work/6_archived/32_story_multi_instance_worktree_support.md diff --git a/.storkit/work/6_archived/330_refactor_consolidate_chat_transports_into_a_chat_module_with_transport_submodules.md b/.huskies/work/6_archived/330_refactor_consolidate_chat_transports_into_a_chat_module_with_transport_submodules.md similarity index 100% rename from .storkit/work/6_archived/330_refactor_consolidate_chat_transports_into_a_chat_module_with_transport_submodules.md rename to .huskies/work/6_archived/330_refactor_consolidate_chat_transports_into_a_chat_module_with_transport_submodules.md diff --git a/.storkit/work/6_archived/331_story_bot_start_command_to_start_a_coder_on_a_story.md b/.huskies/work/6_archived/331_story_bot_start_command_to_start_a_coder_on_a_story.md similarity index 100% rename from .storkit/work/6_archived/331_story_bot_start_command_to_start_a_coder_on_a_story.md rename to .huskies/work/6_archived/331_story_bot_start_command_to_start_a_coder_on_a_story.md diff --git a/.storkit/work/6_archived/332_story_bot_assign_command_to_assign_a_specific_agent_to_a_story.md b/.huskies/work/6_archived/332_story_bot_assign_command_to_assign_a_specific_agent_to_a_story.md similarity index 100% rename from .storkit/work/6_archived/332_story_bot_assign_command_to_assign_a_specific_agent_to_a_story.md rename to .huskies/work/6_archived/332_story_bot_assign_command_to_assign_a_specific_agent_to_a_story.md diff --git a/.storkit/work/6_archived/333_story_bot_stop_command_to_stop_an_agent_on_a_story.md b/.huskies/work/6_archived/333_story_bot_stop_command_to_stop_an_agent_on_a_story.md similarity index 100% rename from .storkit/work/6_archived/333_story_bot_stop_command_to_stop_an_agent_on_a_story.md rename to .huskies/work/6_archived/333_story_bot_stop_command_to_stop_an_agent_on_a_story.md diff --git a/.storkit/work/6_archived/334_story_bot_move_command_to_move_stories_between_pipeline_stages.md b/.huskies/work/6_archived/334_story_bot_move_command_to_move_stories_between_pipeline_stages.md similarity index 100% rename from .storkit/work/6_archived/334_story_bot_move_command_to_move_stories_between_pipeline_stages.md rename to .huskies/work/6_archived/334_story_bot_move_command_to_move_stories_between_pipeline_stages.md diff --git a/.storkit/work/6_archived/335_story_bot_rebuild_command_to_trigger_server_rebuild_and_restart.md b/.huskies/work/6_archived/335_story_bot_rebuild_command_to_trigger_server_rebuild_and_restart.md similarity index 100% rename from .storkit/work/6_archived/335_story_bot_rebuild_command_to_trigger_server_rebuild_and_restart.md rename to .huskies/work/6_archived/335_story_bot_rebuild_command_to_trigger_server_rebuild_and_restart.md diff --git a/.storkit/work/6_archived/336_story_web_ui_button_to_start_a_coder_on_a_story.md b/.huskies/work/6_archived/336_story_web_ui_button_to_start_a_coder_on_a_story.md similarity index 100% rename from .storkit/work/6_archived/336_story_web_ui_button_to_start_a_coder_on_a_story.md rename to .huskies/work/6_archived/336_story_web_ui_button_to_start_a_coder_on_a_story.md diff --git a/.storkit/work/6_archived/337_story_web_ui_button_to_stop_an_agent_on_a_story.md b/.huskies/work/6_archived/337_story_web_ui_button_to_stop_an_agent_on_a_story.md similarity index 100% rename from .storkit/work/6_archived/337_story_web_ui_button_to_stop_an_agent_on_a_story.md rename to .huskies/work/6_archived/337_story_web_ui_button_to_stop_an_agent_on_a_story.md diff --git a/.storkit/work/6_archived/338_story_web_ui_button_to_move_stories_between_pipeline_stages.md b/.huskies/work/6_archived/338_story_web_ui_button_to_move_stories_between_pipeline_stages.md similarity index 100% rename from .storkit/work/6_archived/338_story_web_ui_button_to_move_stories_between_pipeline_stages.md rename to .huskies/work/6_archived/338_story_web_ui_button_to_move_stories_between_pipeline_stages.md diff --git a/.storkit/work/6_archived/339_story_web_ui_agent_assignment_dropdown_on_work_items.md b/.huskies/work/6_archived/339_story_web_ui_agent_assignment_dropdown_on_work_items.md similarity index 100% rename from .storkit/work/6_archived/339_story_web_ui_agent_assignment_dropdown_on_work_items.md rename to .huskies/work/6_archived/339_story_web_ui_agent_assignment_dropdown_on_work_items.md diff --git a/.storkit/work/6_archived/33_story_worktree_diff_integration.md b/.huskies/work/6_archived/33_story_worktree_diff_integration.md similarity index 100% rename from .storkit/work/6_archived/33_story_worktree_diff_integration.md rename to .huskies/work/6_archived/33_story_worktree_diff_integration.md diff --git a/.storkit/work/6_archived/340_story_web_ui_rebuild_and_restart_button.md b/.huskies/work/6_archived/340_story_web_ui_rebuild_and_restart_button.md similarity index 100% rename from .storkit/work/6_archived/340_story_web_ui_rebuild_and_restart_button.md rename to .huskies/work/6_archived/340_story_web_ui_rebuild_and_restart_button.md diff --git a/.storkit/work/6_archived/342_story_web_ui_button_to_delete_a_story_from_the_pipeline.md b/.huskies/work/6_archived/342_story_web_ui_button_to_delete_a_story_from_the_pipeline.md similarity index 100% rename from .storkit/work/6_archived/342_story_web_ui_button_to_delete_a_story_from_the_pipeline.md rename to .huskies/work/6_archived/342_story_web_ui_button_to_delete_a_story_from_the_pipeline.md diff --git a/.storkit/work/6_archived/343_refactor_abstract_agent_runtime_to_support_non_claude_code_backends.md b/.huskies/work/6_archived/343_refactor_abstract_agent_runtime_to_support_non_claude_code_backends.md similarity index 100% rename from .storkit/work/6_archived/343_refactor_abstract_agent_runtime_to_support_non_claude_code_backends.md rename to .huskies/work/6_archived/343_refactor_abstract_agent_runtime_to_support_non_claude_code_backends.md diff --git a/.storkit/work/6_archived/344_story_chatgpt_agent_backend_via_openai_api.md b/.huskies/work/6_archived/344_story_chatgpt_agent_backend_via_openai_api.md similarity index 93% rename from .storkit/work/6_archived/344_story_chatgpt_agent_backend_via_openai_api.md rename to .huskies/work/6_archived/344_story_chatgpt_agent_backend_via_openai_api.md index 8f74c5af..90530192 100644 --- a/.storkit/work/6_archived/344_story_chatgpt_agent_backend_via_openai_api.md +++ b/.huskies/work/6_archived/344_story_chatgpt_agent_backend_via_openai_api.md @@ -14,7 +14,7 @@ As a project owner, I want to run agents using ChatGPT (GPT-4o, o3, etc.) via th - [ ] Implement OpenAiRuntime using the AgentRuntime trait from refactor 343 - [ ] Supports GPT-4o and o3 models via the OpenAI chat completions API - [ ] Manages a conversation loop: send prompt + tool definitions, execute tool calls, continue until done -- [ ] Agents connect to storkit's MCP server for all tool operations — no custom file/bash tools needed +- [ ] Agents connect to huskies's MCP server for all tool operations — no custom file/bash tools needed - [ ] MCP tool definitions are converted to OpenAI function calling format - [ ] Configurable in project.toml: runtime = 'openai', model = 'gpt-4o' - [ ] OPENAI_API_KEY passed via environment variable diff --git a/.storkit/work/6_archived/345_story_gemini_agent_backend_via_google_ai_api.md b/.huskies/work/6_archived/345_story_gemini_agent_backend_via_google_ai_api.md similarity index 94% rename from .storkit/work/6_archived/345_story_gemini_agent_backend_via_google_ai_api.md rename to .huskies/work/6_archived/345_story_gemini_agent_backend_via_google_ai_api.md index 8c1d2fdc..6f892fea 100644 --- a/.storkit/work/6_archived/345_story_gemini_agent_backend_via_google_ai_api.md +++ b/.huskies/work/6_archived/345_story_gemini_agent_backend_via_google_ai_api.md @@ -13,7 +13,7 @@ As a project owner, I want to run agents using Gemini (2.5 Pro, etc.) via the Go - [ ] Implement GeminiRuntime using the AgentRuntime trait from refactor 343 - [ ] Supports Gemini 2.5 Pro and other Gemini models via the Google AI generativeai API - [ ] Manages a conversation loop: send prompt + tool definitions, execute tool calls, continue until done -- [ ] Agents connect to storkit's MCP server for all tool operations — no custom file/bash tools needed +- [ ] Agents connect to huskies's MCP server for all tool operations — no custom file/bash tools needed - [ ] MCP tool definitions are converted to Gemini function calling format - [ ] Configurable in project.toml: runtime = 'gemini', model = 'gemini-2.5-pro' - [ ] GOOGLE_AI_API_KEY passed via environment variable diff --git a/.storkit/work/6_archived/346_story_mcp_tools_for_file_operations_read_write_edit_list.md b/.huskies/work/6_archived/346_story_mcp_tools_for_file_operations_read_write_edit_list.md similarity index 100% rename from .storkit/work/6_archived/346_story_mcp_tools_for_file_operations_read_write_edit_list.md rename to .huskies/work/6_archived/346_story_mcp_tools_for_file_operations_read_write_edit_list.md diff --git a/.storkit/work/6_archived/347_story_mcp_tool_for_shell_command_execution.md b/.huskies/work/6_archived/347_story_mcp_tool_for_shell_command_execution.md similarity index 100% rename from .storkit/work/6_archived/347_story_mcp_tool_for_shell_command_execution.md rename to .huskies/work/6_archived/347_story_mcp_tool_for_shell_command_execution.md diff --git a/.storkit/work/6_archived/348_story_mcp_tools_for_code_search_grep_and_glob.md b/.huskies/work/6_archived/348_story_mcp_tools_for_code_search_grep_and_glob.md similarity index 100% rename from .storkit/work/6_archived/348_story_mcp_tools_for_code_search_grep_and_glob.md rename to .huskies/work/6_archived/348_story_mcp_tools_for_code_search_grep_and_glob.md diff --git a/.storkit/work/6_archived/349_story_mcp_tools_for_git_operations.md b/.huskies/work/6_archived/349_story_mcp_tools_for_git_operations.md similarity index 100% rename from .storkit/work/6_archived/349_story_mcp_tools_for_git_operations.md rename to .huskies/work/6_archived/349_story_mcp_tools_for_git_operations.md diff --git a/.storkit/work/6_archived/34_story_agent_configuration_and_roles.md b/.huskies/work/6_archived/34_story_agent_configuration_and_roles.md similarity index 100% rename from .storkit/work/6_archived/34_story_agent_configuration_and_roles.md rename to .huskies/work/6_archived/34_story_agent_configuration_and_roles.md diff --git a/.storkit/work/6_archived/350_story_mcp_tool_for_code_definitions_lookup.md b/.huskies/work/6_archived/350_story_mcp_tool_for_code_definitions_lookup.md similarity index 100% rename from .storkit/work/6_archived/350_story_mcp_tool_for_code_definitions_lookup.md rename to .huskies/work/6_archived/350_story_mcp_tool_for_code_definitions_lookup.md diff --git a/.storkit/work/6_archived/351_story_bot_reset_command_to_clear_conversation_context.md b/.huskies/work/6_archived/351_story_bot_reset_command_to_clear_conversation_context.md similarity index 100% rename from .storkit/work/6_archived/351_story_bot_reset_command_to_clear_conversation_context.md rename to .huskies/work/6_archived/351_story_bot_reset_command_to_clear_conversation_context.md diff --git a/.storkit/work/6_archived/352_bug_ambient_on_off_command_not_intercepted_by_bot_after_refactors.md b/.huskies/work/6_archived/352_bug_ambient_on_off_command_not_intercepted_by_bot_after_refactors.md similarity index 100% rename from .storkit/work/6_archived/352_bug_ambient_on_off_command_not_intercepted_by_bot_after_refactors.md rename to .huskies/work/6_archived/352_bug_ambient_on_off_command_not_intercepted_by_bot_after_refactors.md diff --git a/.storkit/work/6_archived/353_story_add_party_emoji_to_done_stage_notification_messages.md b/.huskies/work/6_archived/353_story_add_party_emoji_to_done_stage_notification_messages.md similarity index 100% rename from .storkit/work/6_archived/353_story_add_party_emoji_to_done_stage_notification_messages.md rename to .huskies/work/6_archived/353_story_add_party_emoji_to_done_stage_notification_messages.md diff --git a/.storkit/work/6_archived/354_story_make_help_command_output_alphabetical.md b/.huskies/work/6_archived/354_story_make_help_command_output_alphabetical.md similarity index 100% rename from .storkit/work/6_archived/354_story_make_help_command_output_alphabetical.md rename to .huskies/work/6_archived/354_story_make_help_command_output_alphabetical.md diff --git a/.storkit/work/6_archived/355_story_bot_rebuild_command_to_trigger_server_rebuild_and_restart.md b/.huskies/work/6_archived/355_story_bot_rebuild_command_to_trigger_server_rebuild_and_restart.md similarity index 100% rename from .storkit/work/6_archived/355_story_bot_rebuild_command_to_trigger_server_rebuild_and_restart.md rename to .huskies/work/6_archived/355_story_bot_rebuild_command_to_trigger_server_rebuild_and_restart.md diff --git a/.storkit/work/6_archived/356_story_start_command_should_say_queued_not_error_when_all_coders_are_busy.md b/.huskies/work/6_archived/356_story_start_command_should_say_queued_not_error_when_all_coders_are_busy.md similarity index 100% rename from .storkit/work/6_archived/356_story_start_command_should_say_queued_not_error_when_all_coders_are_busy.md rename to .huskies/work/6_archived/356_story_start_command_should_say_queued_not_error_when_all_coders_are_busy.md diff --git a/.storkit/work/6_archived/357_story_bot_assign_command_to_pre_assign_a_model_to_a_story.md b/.huskies/work/6_archived/357_story_bot_assign_command_to_pre_assign_a_model_to_a_story.md similarity index 100% rename from .storkit/work/6_archived/357_story_bot_assign_command_to_pre_assign_a_model_to_a_story.md rename to .huskies/work/6_archived/357_story_bot_assign_command_to_pre_assign_a_model_to_a_story.md diff --git a/.storkit/work/6_archived/358_story_remove_makefile_and_make_script_release_the_single_entry_point_for_releases.md b/.huskies/work/6_archived/358_story_remove_makefile_and_make_script_release_the_single_entry_point_for_releases.md similarity index 100% rename from .storkit/work/6_archived/358_story_remove_makefile_and_make_script_release_the_single_entry_point_for_releases.md rename to .huskies/work/6_archived/358_story_remove_makefile_and_make_script_release_the_single_entry_point_for_releases.md diff --git a/.storkit/work/6_archived/359_story_harden_docker_setup_for_security.md b/.huskies/work/6_archived/359_story_harden_docker_setup_for_security.md similarity index 95% rename from .storkit/work/6_archived/359_story_harden_docker_setup_for_security.md rename to .huskies/work/6_archived/359_story_harden_docker_setup_for_security.md index 3a26a822..07411c1c 100644 --- a/.storkit/work/6_archived/359_story_harden_docker_setup_for_security.md +++ b/.huskies/work/6_archived/359_story_harden_docker_setup_for_security.md @@ -8,7 +8,7 @@ blocked: true ## User Story -As a storkit operator, I want the Docker container to run with hardened security settings, so that a compromised agent or malicious codebase cannot escape the container or affect the host. +As a huskies operator, I want the Docker container to run with hardened security settings, so that a compromised agent or malicious codebase cannot escape the container or affect the host. ## Acceptance Criteria diff --git a/.storkit/work/6_archived/360_story_run_storkit_container_under_gvisor_runsc_runtime.md b/.huskies/work/6_archived/360_story_run_storkit_container_under_gvisor_runsc_runtime.md similarity index 75% rename from .storkit/work/6_archived/360_story_run_storkit_container_under_gvisor_runsc_runtime.md rename to .huskies/work/6_archived/360_story_run_storkit_container_under_gvisor_runsc_runtime.md index a723e033..26fe884a 100644 --- a/.storkit/work/6_archived/360_story_run_storkit_container_under_gvisor_runsc_runtime.md +++ b/.huskies/work/6_archived/360_story_run_storkit_container_under_gvisor_runsc_runtime.md @@ -1,12 +1,12 @@ --- -name: "Run storkit container under gVisor (runsc) runtime" +name: "Run huskies container under gVisor (runsc) runtime" --- -# Story 360: Run storkit container under gVisor (runsc) runtime +# Story 360: Run huskies container under gVisor (runsc) runtime ## User Story -As a storkit operator, I want the container to run under gVisor so that even if a malicious codebase escapes the container's process namespace, it cannot make raw syscalls to the host kernel. +As a huskies operator, I want the container to run under gVisor so that even if a malicious codebase escapes the container's process namespace, it cannot make raw syscalls to the host kernel. ## Acceptance Criteria diff --git a/.storkit/work/6_archived/361_story_remove_deprecated_manual_qa_front_matter_field.md b/.huskies/work/6_archived/361_story_remove_deprecated_manual_qa_front_matter_field.md similarity index 100% rename from .storkit/work/6_archived/361_story_remove_deprecated_manual_qa_front_matter_field.md rename to .huskies/work/6_archived/361_story_remove_deprecated_manual_qa_front_matter_field.md diff --git a/.storkit/work/6_archived/362_story_bot_whatsup_command_shows_in_progress_work_summary.md b/.huskies/work/6_archived/362_story_bot_whatsup_command_shows_in_progress_work_summary.md similarity index 100% rename from .storkit/work/6_archived/362_story_bot_whatsup_command_shows_in_progress_work_summary.md rename to .huskies/work/6_archived/362_story_bot_whatsup_command_shows_in_progress_work_summary.md diff --git a/.storkit/work/6_archived/363_story_mcp_tool_for_whatsup_story_triage.md b/.huskies/work/6_archived/363_story_mcp_tool_for_whatsup_story_triage.md similarity index 100% rename from .storkit/work/6_archived/363_story_mcp_tool_for_whatsup_story_triage.md rename to .huskies/work/6_archived/363_story_mcp_tool_for_whatsup_story_triage.md diff --git a/.storkit/work/6_archived/365_story_surface_api_rate_limit_warnings_in_chat.md b/.huskies/work/6_archived/365_story_surface_api_rate_limit_warnings_in_chat.md similarity index 98% rename from .storkit/work/6_archived/365_story_surface_api_rate_limit_warnings_in_chat.md rename to .huskies/work/6_archived/365_story_surface_api_rate_limit_warnings_in_chat.md index d1174199..d803cf56 100644 --- a/.storkit/work/6_archived/365_story_surface_api_rate_limit_warnings_in_chat.md +++ b/.huskies/work/6_archived/365_story_surface_api_rate_limit_warnings_in_chat.md @@ -48,7 +48,7 @@ These events are already logged as `[pty-debug] raw line:` in the server logs. T ## Test Results - + ### Unit Tests (6 passed, 0 failed) diff --git a/.storkit/work/6_archived/366_story_bot_sends_shutdown_message_on_server_stop_or_rebuild.md b/.huskies/work/6_archived/366_story_bot_sends_shutdown_message_on_server_stop_or_rebuild.md similarity index 100% rename from .storkit/work/6_archived/366_story_bot_sends_shutdown_message_on_server_stop_or_rebuild.md rename to .huskies/work/6_archived/366_story_bot_sends_shutdown_message_on_server_stop_or_rebuild.md diff --git a/.storkit/work/6_archived/367_story_rename_bot_whatsup_command_to_status.md b/.huskies/work/6_archived/367_story_rename_bot_whatsup_command_to_status.md similarity index 100% rename from .storkit/work/6_archived/367_story_rename_bot_whatsup_command_to_status.md rename to .huskies/work/6_archived/367_story_rename_bot_whatsup_command_to_status.md diff --git a/.storkit/work/6_archived/368_story_web_ui_oauth_flow_for_claude_authentication.md b/.huskies/work/6_archived/368_story_web_ui_oauth_flow_for_claude_authentication.md similarity index 94% rename from .storkit/work/6_archived/368_story_web_ui_oauth_flow_for_claude_authentication.md rename to .huskies/work/6_archived/368_story_web_ui_oauth_flow_for_claude_authentication.md index 005b80d0..2981d259 100644 --- a/.storkit/work/6_archived/368_story_web_ui_oauth_flow_for_claude_authentication.md +++ b/.huskies/work/6_archived/368_story_web_ui_oauth_flow_for_claude_authentication.md @@ -7,7 +7,7 @@ agent: "coder-opus" ## User Story -As a new user running storkit in Docker, I want to authenticate Claude through the web UI instead of running `claude login` in a terminal inside the container, so that the entire setup experience stays in the browser after `docker compose up`. +As a new user running huskies in Docker, I want to authenticate Claude through the web UI instead of running `claude login` in a terminal inside the container, so that the entire setup experience stays in the browser after `docker compose up`. ## Acceptance Criteria diff --git a/.storkit/work/6_archived/369_bug_cli_treats_help_and_version_as_project_paths.md b/.huskies/work/6_archived/369_bug_cli_treats_help_and_version_as_project_paths.md similarity index 50% rename from .storkit/work/6_archived/369_bug_cli_treats_help_and_version_as_project_paths.md rename to .huskies/work/6_archived/369_bug_cli_treats_help_and_version_as_project_paths.md index 1bbb82ae..a6c87f23 100644 --- a/.storkit/work/6_archived/369_bug_cli_treats_help_and_version_as_project_paths.md +++ b/.huskies/work/6_archived/369_bug_cli_treats_help_and_version_as_project_paths.md @@ -6,12 +6,12 @@ name: "CLI treats --help and --version as project paths" ## Description -When running `storkit `, the binary treats the first argument as a project path, creates a directory for it, and scaffolds `.storkit/` inside. This happens for `--help`, `--version`, `serve`, `x`, or any other string. There is no validation that the argument is an existing directory or a reasonable path before creating it. +When running `huskies `, the binary treats the first argument as a project path, creates a directory for it, and scaffolds `.huskies/` inside. This happens for `--help`, `--version`, `serve`, `x`, or any other string. There is no validation that the argument is an existing directory or a reasonable path before creating it. ## How to Reproduce -1. Run `storkit --help` or `storkit serve` or `storkit x` in any directory -2. Observe that a directory with that name is created with a full `.storkit/` scaffold inside it +1. Run `huskies --help` or `huskies serve` or `huskies x` in any directory +2. Observe that a directory with that name is created with a full `.huskies/` scaffold inside it ## Actual Result @@ -19,16 +19,16 @@ Any argument is treated as a project path and a directory is created and scaffol ## Expected Result -- `storkit --help` prints usage info and exits -- `storkit --version` prints the version and exits -- `storkit ` only works if the path already exists as a directory -- If the path does not exist, storkit prints a clear error and exits non-zero +- `huskies --help` prints usage info and exits +- `huskies --version` prints the version and exits +- `huskies ` only works if the path already exists as a directory +- If the path does not exist, huskies prints a clear error and exits non-zero ## Acceptance Criteria -- [ ] storkit --help prints usage information and exits with code 0 -- [ ] storkit --version prints the version and exits with code 0 -- [ ] storkit -h and storkit -V work as short aliases -- [ ] storkit does not create directories for any argument — the path must already exist -- [ ] If the path does not exist, storkit prints a clear error and exits non-zero +- [ ] huskies --help prints usage information and exits with code 0 +- [ ] huskies --version prints the version and exits with code 0 +- [ ] huskies -h and huskies -V work as short aliases +- [ ] huskies does not create directories for any argument — the path must already exist +- [ ] If the path does not exist, huskies prints a clear error and exits non-zero - [ ] Arguments starting with - that are not recognised produce a clear error message diff --git a/.storkit/work/6_archived/36_story_enforce_story_front_matter.md b/.huskies/work/6_archived/36_story_enforce_story_front_matter.md similarity index 100% rename from .storkit/work/6_archived/36_story_enforce_story_front_matter.md rename to .huskies/work/6_archived/36_story_enforce_story_front_matter.md diff --git a/.storkit/work/6_archived/370_bug_scaffold_does_not_create_mcp_json_in_project_root.md b/.huskies/work/6_archived/370_bug_scaffold_does_not_create_mcp_json_in_project_root.md similarity index 83% rename from .storkit/work/6_archived/370_bug_scaffold_does_not_create_mcp_json_in_project_root.md rename to .huskies/work/6_archived/370_bug_scaffold_does_not_create_mcp_json_in_project_root.md index 279e5df0..319571ac 100644 --- a/.storkit/work/6_archived/370_bug_scaffold_does_not_create_mcp_json_in_project_root.md +++ b/.huskies/work/6_archived/370_bug_scaffold_does_not_create_mcp_json_in_project_root.md @@ -8,13 +8,13 @@ name: "Scaffold does not create .mcp.json in project root" Two related problems with project setup: -1. When the user clicks the "project setup" button in the web UI to open a new project, the scaffold does not reliably run — the `.storkit/` directory and associated files may not be created. -2. Even when the scaffold does run, it does not write `.mcp.json` to the project root. Without this file, agents spawned in worktrees cannot find the MCP server, causing `--permission-prompt-tool mcp__storkit__prompt_permission not found` errors and agent failures. +1. When the user clicks the "project setup" button in the web UI to open a new project, the scaffold does not reliably run — the `.huskies/` directory and associated files may not be created. +2. Even when the scaffold does run, it does not write `.mcp.json` to the project root. Without this file, agents spawned in worktrees cannot find the MCP server, causing `--permission-prompt-tool mcp__huskies__prompt_permission not found` errors and agent failures. ## How to Reproduce -1. Open the storkit web UI and use the project setup button to open a new project directory -2. Check whether the full scaffold was created (`.storkit/`, `CLAUDE.md`, `script/test`, etc.) +1. Open the huskies web UI and use the project setup button to open a new project directory +2. Check whether the full scaffold was created (`.huskies/`, `CLAUDE.md`, `script/test`, etc.) 3. Check the project root for `.mcp.json` ## Actual Result diff --git a/.huskies/work/6_archived/371_bug_no_arg_storkit_in_empty_directory_skips_scaffold.md b/.huskies/work/6_archived/371_bug_no_arg_storkit_in_empty_directory_skips_scaffold.md new file mode 100644 index 00000000..9e7200df --- /dev/null +++ b/.huskies/work/6_archived/371_bug_no_arg_storkit_in_empty_directory_skips_scaffold.md @@ -0,0 +1,32 @@ +--- +name: "No-arg huskies in empty directory skips scaffold" +--- + +# Bug 371: No-arg huskies in empty directory skips scaffold + +## Description + +When running `huskies` with no path argument from an empty directory (no `.huskies/`), the server starts but never calls `open_project` or the scaffold. The `find_story_kit_root` check fails to find `.huskies/`, so the fallback at main.rs:179-186 just sets `project_root = cwd` without scaffolding. This means no `.huskies/`, no `project.toml`, no `.mcp.json`, no `CLAUDE.md` — the project is non-functional. + +The explicit path branch (`huskies .`) works correctly because it calls `open_project` → `ensure_project_root_with_story_kit` → `scaffold_story_kit`. The no-arg branch should do the same. + +## How to Reproduce + +1. Create a new empty directory +2. cd into it +3. Run `huskies` (no path argument) +4. Observe that no scaffold is created — `.huskies/`, `CLAUDE.md`, `.mcp.json`, etc. are all missing + +## Actual Result + +Server starts with project_root set to cwd but no scaffold runs. The project is non-functional — no agent config, no MCP endpoint, no work pipeline directories. + +## Expected Result + +Running `huskies` with no arguments from a directory without `.huskies/` should scaffold the project the same as `huskies .` does — calling `open_project` and triggering `ensure_project_root_with_story_kit`. + +## Acceptance Criteria + +- [ ] Running `huskies` with no args from a dir without `.huskies/` calls `open_project` and triggers the full scaffold +- [ ] The no-arg fallback path in main.rs calls `open_project(cwd)` instead of just setting project_root directly +- [ ] After `huskies` completes startup, `.huskies/project.toml`, `.mcp.json`, `CLAUDE.md`, and `script/test` all exist diff --git a/.storkit/work/6_archived/372_story_scaffold_auto_detects_tech_stack_and_configures_script_test.md b/.huskies/work/6_archived/372_story_scaffold_auto_detects_tech_stack_and_configures_script_test.md similarity index 94% rename from .storkit/work/6_archived/372_story_scaffold_auto_detects_tech_stack_and_configures_script_test.md rename to .huskies/work/6_archived/372_story_scaffold_auto_detects_tech_stack_and_configures_script_test.md index 11272c13..cc7823c2 100644 --- a/.storkit/work/6_archived/372_story_scaffold_auto_detects_tech_stack_and_configures_script_test.md +++ b/.huskies/work/6_archived/372_story_scaffold_auto_detects_tech_stack_and_configures_script_test.md @@ -6,7 +6,7 @@ name: "Scaffold auto-detects tech stack and configures script/test" ## User Story -As a user setting up a new project with storkit, I want the scaffold to detect my project's tech stack and generate a working `script/test` automatically, so that agents can run tests immediately without manual configuration. +As a user setting up a new project with huskies, I want the scaffold to detect my project's tech stack and generate a working `script/test` automatically, so that agents can run tests immediately without manual configuration. ## Acceptance Criteria diff --git a/.storkit/work/6_archived/373_bug_scaffold_gitignore_missing_transient_pipeline_stage_directories.md b/.huskies/work/6_archived/373_bug_scaffold_gitignore_missing_transient_pipeline_stage_directories.md similarity index 71% rename from .storkit/work/6_archived/373_bug_scaffold_gitignore_missing_transient_pipeline_stage_directories.md rename to .huskies/work/6_archived/373_bug_scaffold_gitignore_missing_transient_pipeline_stage_directories.md index 85666705..aed62176 100644 --- a/.storkit/work/6_archived/373_bug_scaffold_gitignore_missing_transient_pipeline_stage_directories.md +++ b/.huskies/work/6_archived/373_bug_scaffold_gitignore_missing_transient_pipeline_stage_directories.md @@ -6,23 +6,23 @@ name: "Scaffold gitignore missing transient pipeline stage directories" ## Description -The `write_story_kit_gitignore` function in `server/src/io/fs.rs` does not include the transient pipeline stages (`work/2_current/`, `work/3_qa/`, `work/4_merge/`) in the `.storkit/.gitignore` entries list. These stages are not committed to git (only `1_backlog`, `5_done`, and `6_archived` are commit-worthy per spike 92), so they should be ignored for new projects. +The `write_story_kit_gitignore` function in `server/src/io/fs.rs` does not include the transient pipeline stages (`work/2_current/`, `work/3_qa/`, `work/4_merge/`) in the `.huskies/.gitignore` entries list. These stages are not committed to git (only `1_backlog`, `5_done`, and `6_archived` are commit-worthy per spike 92), so they should be ignored for new projects. ## How to Reproduce -1. Scaffold a new project with storkit -2. Check `.storkit/.gitignore` +1. Scaffold a new project with huskies +2. Check `.huskies/.gitignore` ## Actual Result -`.storkit/.gitignore` only contains `bot.toml`, `matrix_store/`, `matrix_device_id`, `worktrees/`, `merge_workspace/`, `coverage/`. The transient pipeline directories are missing. +`.huskies/.gitignore` only contains `bot.toml`, `matrix_store/`, `matrix_device_id`, `worktrees/`, `merge_workspace/`, `coverage/`. The transient pipeline directories are missing. ## Expected Result -`.storkit/.gitignore` also includes `work/2_current/`, `work/3_qa/`, `work/4_merge/`. +`.huskies/.gitignore` also includes `work/2_current/`, `work/3_qa/`, `work/4_merge/`. ## Acceptance Criteria -- [ ] Scaffold writes work/2_current/, work/3_qa/, work/4_merge/ to .storkit/.gitignore +- [ ] Scaffold writes work/2_current/, work/3_qa/, work/4_merge/ to .huskies/.gitignore - [ ] Idempotent — running scaffold again does not duplicate entries -- [ ] Existing .storkit/.gitignore files get the new entries appended on next scaffold run +- [ ] Existing .huskies/.gitignore files get the new entries appended on next scaffold run diff --git a/.storkit/work/6_archived/374_story_web_ui_implements_all_bot_commands_as_slash_commands.md b/.huskies/work/6_archived/374_story_web_ui_implements_all_bot_commands_as_slash_commands.md similarity index 95% rename from .storkit/work/6_archived/374_story_web_ui_implements_all_bot_commands_as_slash_commands.md rename to .huskies/work/6_archived/374_story_web_ui_implements_all_bot_commands_as_slash_commands.md index 668a527b..87a67358 100644 --- a/.storkit/work/6_archived/374_story_web_ui_implements_all_bot_commands_as_slash_commands.md +++ b/.huskies/work/6_archived/374_story_web_ui_implements_all_bot_commands_as_slash_commands.md @@ -6,7 +6,7 @@ name: "Web UI implements all bot commands as slash commands" ## User Story -As a user working in the storkit web UI, I want to type slash commands (e.g. `/status`, `/start 42`, `/cost`) in the chat input to trigger the same deterministic bot commands available in Matrix, so that I can manage my project entirely from the browser without needing a chat bot. +As a user working in the huskies web UI, I want to type slash commands (e.g. `/status`, `/start 42`, `/cost`) in the chat input to trigger the same deterministic bot commands available in Matrix, so that I can manage my project entirely from the browser without needing a chat bot. ## Acceptance Criteria diff --git a/.storkit/work/6_archived/375_bug_default_project_toml_contains_rust_specific_setup_commands_for_non_rust_projects.md b/.huskies/work/6_archived/375_bug_default_project_toml_contains_rust_specific_setup_commands_for_non_rust_projects.md similarity index 95% rename from .storkit/work/6_archived/375_bug_default_project_toml_contains_rust_specific_setup_commands_for_non_rust_projects.md rename to .huskies/work/6_archived/375_bug_default_project_toml_contains_rust_specific_setup_commands_for_non_rust_projects.md index 2c2c3c60..b2de9692 100644 --- a/.storkit/work/6_archived/375_bug_default_project_toml_contains_rust_specific_setup_commands_for_non_rust_projects.md +++ b/.huskies/work/6_archived/375_bug_default_project_toml_contains_rust_specific_setup_commands_for_non_rust_projects.md @@ -23,8 +23,8 @@ When scaffolding a new project where no tech stack is detected, the generated `p ## How to Reproduce 1. Create a new Go + Next.js project directory with `go.mod` and `package.json` -2. Run `storkit .` to scaffold -3. Check `.storkit/project.toml` — the component setup commands reference cargo/Rust +2. Run `huskies .` to scaffold +3. Check `.huskies/project.toml` — the component setup commands reference cargo/Rust 4. Start a coder agent — it creates a `Cargo.toml` trying to satisfy the Rust setup commands ## Actual Result diff --git a/.storkit/work/6_archived/376_story_rename_mcp_whatsup_tool_to_status_for_consistency.md b/.huskies/work/6_archived/376_story_rename_mcp_whatsup_tool_to_status_for_consistency.md similarity index 91% rename from .storkit/work/6_archived/376_story_rename_mcp_whatsup_tool_to_status_for_consistency.md rename to .huskies/work/6_archived/376_story_rename_mcp_whatsup_tool_to_status_for_consistency.md index 8118038b..19886673 100644 --- a/.storkit/work/6_archived/376_story_rename_mcp_whatsup_tool_to_status_for_consistency.md +++ b/.huskies/work/6_archived/376_story_rename_mcp_whatsup_tool_to_status_for_consistency.md @@ -7,7 +7,7 @@ agent: coder-opus ## User Story -As a developer using storkit's MCP tools, I want the MCP tool to be called `status` instead of `whatsup`, so that the naming is consistent between the bot command (`status`), the web UI slash command (`/status`), and the MCP tool. +As a developer using huskies's MCP tools, I want the MCP tool to be called `status` instead of `whatsup`, so that the naming is consistent between the bot command (`status`), the web UI slash command (`/status`), and the MCP tool. ## Acceptance Criteria diff --git a/.storkit/work/6_archived/377_bug_update_story_mcp_tool_writes_front_matter_values_as_yaml_strings_instead_of_native_types.md b/.huskies/work/6_archived/377_bug_update_story_mcp_tool_writes_front_matter_values_as_yaml_strings_instead_of_native_types.md similarity index 100% rename from .storkit/work/6_archived/377_bug_update_story_mcp_tool_writes_front_matter_values_as_yaml_strings_instead_of_native_types.md rename to .huskies/work/6_archived/377_bug_update_story_mcp_tool_writes_front_matter_values_as_yaml_strings_instead_of_native_types.md diff --git a/.storkit/work/6_archived/378_story_status_command_shows_work_item_type_story_bug_spike_refactor_next_to_each_item.md b/.huskies/work/6_archived/378_story_status_command_shows_work_item_type_story_bug_spike_refactor_next_to_each_item.md similarity index 100% rename from .storkit/work/6_archived/378_story_status_command_shows_work_item_type_story_bug_spike_refactor_next_to_each_item.md rename to .huskies/work/6_archived/378_story_status_command_shows_work_item_type_story_bug_spike_refactor_next_to_each_item.md diff --git a/.storkit/work/6_archived/379_bug_start_agent_ignores_story_front_matter_agent_assignment.md b/.huskies/work/6_archived/379_bug_start_agent_ignores_story_front_matter_agent_assignment.md similarity index 100% rename from .storkit/work/6_archived/379_bug_start_agent_ignores_story_front_matter_agent_assignment.md rename to .huskies/work/6_archived/379_bug_start_agent_ignores_story_front_matter_agent_assignment.md diff --git a/.storkit/work/6_archived/37_story_editor_command_for_worktrees.md b/.huskies/work/6_archived/37_story_editor_command_for_worktrees.md similarity index 100% rename from .storkit/work/6_archived/37_story_editor_command_for_worktrees.md rename to .huskies/work/6_archived/37_story_editor_command_for_worktrees.md diff --git a/.storkit/work/6_archived/380_story_assign_command_restarts_coder_when_story_is_already_in_progress.md b/.huskies/work/6_archived/380_story_assign_command_restarts_coder_when_story_is_already_in_progress.md similarity index 100% rename from .storkit/work/6_archived/380_story_assign_command_restarts_coder_when_story_is_already_in_progress.md rename to .huskies/work/6_archived/380_story_assign_command_restarts_coder_when_story_is_already_in_progress.md diff --git a/.storkit/work/6_archived/381_story_bot_command_to_delete_a_worktree.md b/.huskies/work/6_archived/381_story_bot_command_to_delete_a_worktree.md similarity index 100% rename from .storkit/work/6_archived/381_story_bot_command_to_delete_a_worktree.md rename to .huskies/work/6_archived/381_story_bot_command_to_delete_a_worktree.md diff --git a/.storkit/work/6_archived/382_story_whatsapp_transport_supports_twilio_api_as_alternative_to_meta_cloud_api.md b/.huskies/work/6_archived/382_story_whatsapp_transport_supports_twilio_api_as_alternative_to_meta_cloud_api.md similarity index 100% rename from .storkit/work/6_archived/382_story_whatsapp_transport_supports_twilio_api_as_alternative_to_meta_cloud_api.md rename to .huskies/work/6_archived/382_story_whatsapp_transport_supports_twilio_api_as_alternative_to_meta_cloud_api.md diff --git a/.storkit/work/6_archived/383_refactor_reorganize_chat_system_into_chat_module_with_transport_submodules.md b/.huskies/work/6_archived/383_refactor_reorganize_chat_system_into_chat_module_with_transport_submodules.md similarity index 100% rename from .storkit/work/6_archived/383_refactor_reorganize_chat_system_into_chat_module_with_transport_submodules.md rename to .huskies/work/6_archived/383_refactor_reorganize_chat_system_into_chat_module_with_transport_submodules.md diff --git a/.storkit/work/6_archived/384_story_whatsapp_markdown_to_whatsapp_formatting_conversion.md b/.huskies/work/6_archived/384_story_whatsapp_markdown_to_whatsapp_formatting_conversion.md similarity index 100% rename from .storkit/work/6_archived/384_story_whatsapp_markdown_to_whatsapp_formatting_conversion.md rename to .huskies/work/6_archived/384_story_whatsapp_markdown_to_whatsapp_formatting_conversion.md diff --git a/.storkit/work/6_archived/385_story_slack_markdown_to_mrkdwn_formatting_conversion.md b/.huskies/work/6_archived/385_story_slack_markdown_to_mrkdwn_formatting_conversion.md similarity index 100% rename from .storkit/work/6_archived/385_story_slack_markdown_to_mrkdwn_formatting_conversion.md rename to .huskies/work/6_archived/385_story_slack_markdown_to_mrkdwn_formatting_conversion.md diff --git a/.storkit/work/6_archived/386_story_unreleased_command_shows_list_of_stories_since_last_release.md b/.huskies/work/6_archived/386_story_unreleased_command_shows_list_of_stories_since_last_release.md similarity index 100% rename from .storkit/work/6_archived/386_story_unreleased_command_shows_list_of_stories_since_last_release.md rename to .huskies/work/6_archived/386_story_unreleased_command_shows_list_of_stories_since_last_release.md diff --git a/.storkit/work/6_archived/387_story_configurable_base_branch_name_in_project_toml.md b/.huskies/work/6_archived/387_story_configurable_base_branch_name_in_project_toml.md similarity index 100% rename from .storkit/work/6_archived/387_story_configurable_base_branch_name_in_project_toml.md rename to .huskies/work/6_archived/387_story_configurable_base_branch_name_in_project_toml.md diff --git a/.storkit/work/6_archived/389_story_whatsapp_phone_number_allowlist_authorization.md b/.huskies/work/6_archived/389_story_whatsapp_phone_number_allowlist_authorization.md similarity index 100% rename from .storkit/work/6_archived/389_story_whatsapp_phone_number_allowlist_authorization.md rename to .huskies/work/6_archived/389_story_whatsapp_phone_number_allowlist_authorization.md diff --git a/.storkit/work/6_archived/38_story_auto_open_project_on_server_startup.md b/.huskies/work/6_archived/38_story_auto_open_project_on_server_startup.md similarity index 100% rename from .storkit/work/6_archived/38_story_auto_open_project_on_server_startup.md rename to .huskies/work/6_archived/38_story_auto_open_project_on_server_startup.md diff --git a/.storkit/work/6_archived/390_bug_whatsapp_missing_async_command_handlers_for_start_rebuild_reset_rmtree_assign.md b/.huskies/work/6_archived/390_bug_whatsapp_missing_async_command_handlers_for_start_rebuild_reset_rmtree_assign.md similarity index 100% rename from .storkit/work/6_archived/390_bug_whatsapp_missing_async_command_handlers_for_start_rebuild_reset_rmtree_assign.md rename to .huskies/work/6_archived/390_bug_whatsapp_missing_async_command_handlers_for_start_rebuild_reset_rmtree_assign.md diff --git a/.storkit/work/6_archived/391_bug_strip_prefix_ci_panics_on_multi_byte_utf_8_characters.md b/.huskies/work/6_archived/391_bug_strip_prefix_ci_panics_on_multi_byte_utf_8_characters.md similarity index 100% rename from .storkit/work/6_archived/391_bug_strip_prefix_ci_panics_on_multi_byte_utf_8_characters.md rename to .huskies/work/6_archived/391_bug_strip_prefix_ci_panics_on_multi_byte_utf_8_characters.md diff --git a/.storkit/work/6_archived/392_refactor_extract_shared_transport_utilities_from_matrix_module_into_chat_submodule.md b/.huskies/work/6_archived/392_refactor_extract_shared_transport_utilities_from_matrix_module_into_chat_submodule.md similarity index 100% rename from .storkit/work/6_archived/392_refactor_extract_shared_transport_utilities_from_matrix_module_into_chat_submodule.md rename to .huskies/work/6_archived/392_refactor_extract_shared_transport_utilities_from_matrix_module_into_chat_submodule.md diff --git a/.storkit/work/6_archived/393_story_pipeline_stage_notifications_for_whatsapp_and_slack_transports.md b/.huskies/work/6_archived/393_story_pipeline_stage_notifications_for_whatsapp_and_slack_transports.md similarity index 100% rename from .storkit/work/6_archived/393_story_pipeline_stage_notifications_for_whatsapp_and_slack_transports.md rename to .huskies/work/6_archived/393_story_pipeline_stage_notifications_for_whatsapp_and_slack_transports.md diff --git a/.storkit/work/6_archived/394_story_whatsapp_and_slack_permission_prompt_forwarding.md b/.huskies/work/6_archived/394_story_whatsapp_and_slack_permission_prompt_forwarding.md similarity index 100% rename from .storkit/work/6_archived/394_story_whatsapp_and_slack_permission_prompt_forwarding.md rename to .huskies/work/6_archived/394_story_whatsapp_and_slack_permission_prompt_forwarding.md diff --git a/.storkit/work/6_archived/395_refactor_fix_npm_deprecated_module_warnings.md b/.huskies/work/6_archived/395_refactor_fix_npm_deprecated_module_warnings.md similarity index 100% rename from .storkit/work/6_archived/395_refactor_fix_npm_deprecated_module_warnings.md rename to .huskies/work/6_archived/395_refactor_fix_npm_deprecated_module_warnings.md diff --git a/.storkit/work/6_archived/396_story_whatsapp_bot_startup_announcement_after_restart.md b/.huskies/work/6_archived/396_story_whatsapp_bot_startup_announcement_after_restart.md similarity index 100% rename from .storkit/work/6_archived/396_story_whatsapp_bot_startup_announcement_after_restart.md rename to .huskies/work/6_archived/396_story_whatsapp_bot_startup_announcement_after_restart.md diff --git a/.storkit/work/6_archived/397_bug_selection_screen_directory_picker_unreadable_in_dark_mode.md b/.huskies/work/6_archived/397_bug_selection_screen_directory_picker_unreadable_in_dark_mode.md similarity index 96% rename from .storkit/work/6_archived/397_bug_selection_screen_directory_picker_unreadable_in_dark_mode.md rename to .huskies/work/6_archived/397_bug_selection_screen_directory_picker_unreadable_in_dark_mode.md index d66608a2..df6bee22 100644 --- a/.storkit/work/6_archived/397_bug_selection_screen_directory_picker_unreadable_in_dark_mode.md +++ b/.huskies/work/6_archived/397_bug_selection_screen_directory_picker_unreadable_in_dark_mode.md @@ -10,7 +10,7 @@ The ProjectPathInput component in the selection screen uses hardcoded light-them ## How to Reproduce -1. Run storkit under Docker (or locally) with a browser set to dark mode (prefers-color-scheme: dark). +1. Run huskies under Docker (or locally) with a browser set to dark mode (prefers-color-scheme: dark). 2. Open http://localhost:3001 in the browser. 3. Click into the project path input and start typing a path to trigger the autocomplete dropdown. diff --git a/.storkit/work/6_archived/399_story_cli_port_flag_with_project_toml_persistence.md b/.huskies/work/6_archived/399_story_cli_port_flag_with_project_toml_persistence.md similarity index 86% rename from .storkit/work/6_archived/399_story_cli_port_flag_with_project_toml_persistence.md rename to .huskies/work/6_archived/399_story_cli_port_flag_with_project_toml_persistence.md index 36953010..2bf3426e 100644 --- a/.storkit/work/6_archived/399_story_cli_port_flag_with_project_toml_persistence.md +++ b/.huskies/work/6_archived/399_story_cli_port_flag_with_project_toml_persistence.md @@ -10,14 +10,14 @@ As a developer, I want to set the server port via a --port CLI flag that persist ## Acceptance Criteria -- [ ] `storkit --help` shows a `--port` option -- [ ] `storkit --port 4000` starts the server on port 4000 +- [ ] `huskies --help` shows a `--port` option +- [ ] `huskies --port 4000` starts the server on port 4000 - [ ] After first run with `--port`, the port is saved to `project.toml` - [ ] On subsequent runs without `--port`, the port from `project.toml` is used - [ ] CLI `--port` overrides the value in `project.toml` - [ ] Default port is 3001 when neither `--port` nor `project.toml` port is set - [ ] `STORKIT_PORT` env var is removed — no longer read or respected -- [ ] `.storkit_port` lock file mechanism is removed (`write_port_file` / `remove_port_file`) +- [ ] `.huskies_port` lock file mechanism is removed (`write_port_file` / `remove_port_file`) ## Out of Scope diff --git a/.storkit/work/6_archived/39_story_persistent_claude_code_sessions_in_web_ui.md b/.huskies/work/6_archived/39_story_persistent_claude_code_sessions_in_web_ui.md similarity index 100% rename from .storkit/work/6_archived/39_story_persistent_claude_code_sessions_in_web_ui.md rename to .huskies/work/6_archived/39_story_persistent_claude_code_sessions_in_web_ui.md diff --git a/.storkit/work/6_archived/3_bug_stale_worktree_blocks_agent_start.md b/.huskies/work/6_archived/3_bug_stale_worktree_blocks_agent_start.md similarity index 100% rename from .storkit/work/6_archived/3_bug_stale_worktree_blocks_agent_start.md rename to .huskies/work/6_archived/3_bug_stale_worktree_blocks_agent_start.md diff --git a/.storkit/work/6_archived/400_bug_whatsapp_and_slack_missing_reset_command_handler.md b/.huskies/work/6_archived/400_bug_whatsapp_and_slack_missing_reset_command_handler.md similarity index 95% rename from .storkit/work/6_archived/400_bug_whatsapp_and_slack_missing_reset_command_handler.md rename to .huskies/work/6_archived/400_bug_whatsapp_and_slack_missing_reset_command_handler.md index 0fc8931c..aea55296 100644 --- a/.storkit/work/6_archived/400_bug_whatsapp_and_slack_missing_reset_command_handler.md +++ b/.huskies/work/6_archived/400_bug_whatsapp_and_slack_missing_reset_command_handler.md @@ -14,11 +14,11 @@ Follow the **rebuild pattern** established in story 402, with one complication: **WhatsApp session storage** (`server/src/chat/transport/whatsapp.rs`): - Type: `WhatsAppConversationHistory = Arc>>` (key = sender phone number) -- Persisted to `.storkit/whatsapp_history.json` via `save_whatsapp_history` +- Persisted to `.huskies/whatsapp_history.json` via `save_whatsapp_history` **Slack session storage** (`server/src/chat/transport/slack.rs`): - Type: `SlackConversationHistory = Arc>>` (key = channel ID) -- Persisted to `.storkit/slack_history.json` via `save_slack_history` +- Persisted to `.huskies/slack_history.json` via `save_slack_history` **Approach:** - Use `extract_reset_command` from `server/src/chat/transport/matrix/reset.rs` to detect the command (it works transport-agnostically) diff --git a/.storkit/work/6_archived/401_bug_whatsapp_and_slack_missing_start_command_handler.md b/.huskies/work/6_archived/401_bug_whatsapp_and_slack_missing_start_command_handler.md similarity index 100% rename from .storkit/work/6_archived/401_bug_whatsapp_and_slack_missing_start_command_handler.md rename to .huskies/work/6_archived/401_bug_whatsapp_and_slack_missing_start_command_handler.md diff --git a/.storkit/work/6_archived/402_bug_whatsapp_and_slack_missing_rebuild_command_handler.md b/.huskies/work/6_archived/402_bug_whatsapp_and_slack_missing_rebuild_command_handler.md similarity index 100% rename from .storkit/work/6_archived/402_bug_whatsapp_and_slack_missing_rebuild_command_handler.md rename to .huskies/work/6_archived/402_bug_whatsapp_and_slack_missing_rebuild_command_handler.md diff --git a/.storkit/work/6_archived/403_bug_whatsapp_and_slack_missing_rmtree_command_handler.md b/.huskies/work/6_archived/403_bug_whatsapp_and_slack_missing_rmtree_command_handler.md similarity index 100% rename from .storkit/work/6_archived/403_bug_whatsapp_and_slack_missing_rmtree_command_handler.md rename to .huskies/work/6_archived/403_bug_whatsapp_and_slack_missing_rmtree_command_handler.md diff --git a/.storkit/work/6_archived/404_bug_whatsapp_and_slack_missing_assign_command_handler.md b/.huskies/work/6_archived/404_bug_whatsapp_and_slack_missing_assign_command_handler.md similarity index 100% rename from .storkit/work/6_archived/404_bug_whatsapp_and_slack_missing_assign_command_handler.md rename to .huskies/work/6_archived/404_bug_whatsapp_and_slack_missing_assign_command_handler.md diff --git a/.storkit/work/6_archived/405_story_auto_refresh_expired_oauth_token_for_claude_code_pty.md b/.huskies/work/6_archived/405_story_auto_refresh_expired_oauth_token_for_claude_code_pty.md similarity index 71% rename from .storkit/work/6_archived/405_story_auto_refresh_expired_oauth_token_for_claude_code_pty.md rename to .huskies/work/6_archived/405_story_auto_refresh_expired_oauth_token_for_claude_code_pty.md index 636dd2ab..e1ec406f 100644 --- a/.storkit/work/6_archived/405_story_auto_refresh_expired_oauth_token_for_claude_code_pty.md +++ b/.huskies/work/6_archived/405_story_auto_refresh_expired_oauth_token_for_claude_code_pty.md @@ -6,25 +6,25 @@ name: "Auto-refresh expired OAuth token for Claude Code PTY" ## User Story -As a storkit user with a Claude Max subscription, I want the server to automatically refresh my expired OAuth token so that chat, Matrix, and WhatsApp integrations don't stop working when the token expires. +As a huskies user with a Claude Max subscription, I want the server to automatically refresh my expired OAuth token so that chat, Matrix, and WhatsApp integrations don't stop working when the token expires. ## Acceptance Criteria ### Detection -- [ ] When the Claude Code PTY returns an `authentication_failed` error, storkit detects it instead of passing the raw 401 JSON to the user +- [ ] When the Claude Code PTY returns an `authentication_failed` error, huskies detects it instead of passing the raw 401 JSON to the user ### Auto-refresh (credentials exist, refresh token valid) -- [ ] Storkit reads the OAuth refresh token from `~/.claude/.credentials.json` -- [ ] Storkit calls the Anthropic OAuth token refresh endpoint (`https://console.anthropic.com/v1/oauth/token` with `grant_type=refresh_token`) to obtain a new access token -- [ ] Storkit writes the refreshed access token (and new expiresAt) back to `~/.claude/.credentials.json` -- [ ] After a successful refresh, storkit automatically retries the original chat request +- [ ] Huskies reads the OAuth refresh token from `~/.claude/.credentials.json` +- [ ] Huskies calls the Anthropic OAuth token refresh endpoint (`https://console.anthropic.com/v1/oauth/token` with `grant_type=refresh_token`) to obtain a new access token +- [ ] Huskies writes the refreshed access token (and new expiresAt) back to `~/.claude/.credentials.json` +- [ ] After a successful refresh, huskies automatically retries the original chat request - [ ] The refresh+retry is transparent to the user — they see no error ### Full login required (no credentials, or refresh token also expired) -- [ ] If `.credentials.json` doesn't exist or the refresh call itself fails, storkit surfaces a clear error: "OAuth session expired. Please run `claude login` to re-authenticate." +- [ ] If `.credentials.json` doesn't exist or the refresh call itself fails, huskies surfaces a clear error: "OAuth session expired. Please run `claude login` to re-authenticate." - [ ] The error message is surfaced through the normal chat stream (not just server logs) ## Out of Scope -- Implementing the full interactive `claude login` browser OAuth flow inside storkit +- Implementing the full interactive `claude login` browser OAuth flow inside huskies - Proactive token refresh before expiry (refreshing on demand when the error occurs is sufficient) diff --git a/.storkit/work/6_archived/406_story_browser_based_oauth_login_flow_from_web_ui_and_chat_integrations.md b/.huskies/work/6_archived/406_story_browser_based_oauth_login_flow_from_web_ui_and_chat_integrations.md similarity index 71% rename from .storkit/work/6_archived/406_story_browser_based_oauth_login_flow_from_web_ui_and_chat_integrations.md rename to .huskies/work/6_archived/406_story_browser_based_oauth_login_flow_from_web_ui_and_chat_integrations.md index 6195f9e3..d5ad450e 100644 --- a/.storkit/work/6_archived/406_story_browser_based_oauth_login_flow_from_web_ui_and_chat_integrations.md +++ b/.huskies/work/6_archived/406_story_browser_based_oauth_login_flow_from_web_ui_and_chat_integrations.md @@ -6,14 +6,14 @@ name: "Browser-based OAuth login flow from web UI and chat integrations" ## User Story -As a new storkit user (or one whose refresh token has expired), I want to complete the full Claude OAuth login flow from the web UI, Matrix, or WhatsApp so that I don't need terminal access to run `claude login`. +As a new huskies user (or one whose refresh token has expired), I want to complete the full Claude OAuth login flow from the web UI, Matrix, or WhatsApp so that I don't need terminal access to run `claude login`. ## Acceptance Criteria -- [ ] From the web UI, the user can initiate OAuth login — storkit generates the Anthropic authorize URL and opens it in a new tab +- [ ] From the web UI, the user can initiate OAuth login — huskies generates the Anthropic authorize URL and opens it in a new tab - [ ] After the user authenticates in the browser, the OAuth callback writes accessToken, refreshToken, and expiresAt to ~/.claude/.credentials.json -- [ ] From Matrix or WhatsApp, storkit sends the user a clickable OAuth authorize link when credentials are missing or fully expired -- [ ] After successful login, the user can immediately start chatting without restarting storkit +- [ ] From Matrix or WhatsApp, huskies sends the user a clickable OAuth authorize link when credentials are missing or fully expired +- [ ] After successful login, the user can immediately start chatting without restarting huskies - [ ] If the OAuth callback fails or the user cancels, a clear error is shown ## Out of Scope diff --git a/.storkit/work/6_archived/407_spike_fly_io_machines_for_multi_tenant_storkit_saas.md b/.huskies/work/6_archived/407_spike_fly_io_machines_for_multi_tenant_storkit_saas.md similarity index 97% rename from .storkit/work/6_archived/407_spike_fly_io_machines_for_multi_tenant_storkit_saas.md rename to .huskies/work/6_archived/407_spike_fly_io_machines_for_multi_tenant_storkit_saas.md index b6136dc8..8a4756f7 100644 --- a/.storkit/work/6_archived/407_spike_fly_io_machines_for_multi_tenant_storkit_saas.md +++ b/.huskies/work/6_archived/407_spike_fly_io_machines_for_multi_tenant_storkit_saas.md @@ -1,14 +1,14 @@ --- -name: "Fly.io Machines for multi-tenant storkit SaaS — docs, security & pricing" +name: "Fly.io Machines for multi-tenant huskies SaaS — docs, security & pricing" retry_count: 2 blocked: true --- -# Spike 407: Fly.io Machines for multi-tenant storkit SaaS — docs, security & pricing +# Spike 407: Fly.io Machines for multi-tenant huskies SaaS — docs, security & pricing ## Question -What do Fly.io's published docs, security claims, and pricing say about using Machines as the isolation layer for a multi-tenant storkit SaaS? Is there anything that rules it out before we write code? +What do Fly.io's published docs, security claims, and pricing say about using Machines as the isolation layer for a multi-tenant huskies SaaS? Is there anything that rules it out before we write code? ## Hypothesis @@ -179,12 +179,12 @@ At scale, volume storage becomes the dominant cost when machines are idle. At 1, ## Recommendation -**Proceed.** Fly.io Machines are a viable isolation layer for multi-tenant storkit SaaS. +**Proceed.** Fly.io Machines are a viable isolation layer for multi-tenant huskies SaaS. **Architecture to validate in spike 408:** - One Fly.io app per tenant (provides 6PN network isolation + isolated secrets) - One Firecracker microVM per tenant app (shared-cpu-1x 256 MB baseline; adjust per observed usage) -- One persistent volume per tenant (1 GB baseline for `~/.claude/`, repos, storkit state) +- One persistent volume per tenant (1 GB baseline for `~/.claude/`, repos, huskies state) - Autostop/autoresume enabled — 70–92% compute cost reduction vs always-on for typical dev tool usage - Tenant credentials injected via `config.files` + Fly Secrets at machine start @@ -192,4 +192,4 @@ At scale, volume storage becomes the dominant cost when machines are idle. At 1, **Before production**: Confirm with Fly.io support whether SMT is disabled on worker hosts. Request org machine limit raised to 200–500 during private beta. -**Spike 408 scope**: Validate cold start latency, autostop resume behavior, and volume persistence with a real test machine running the storkit container image. +**Spike 408 scope**: Validate cold start latency, autostop resume behavior, and volume persistence with a real test machine running the huskies container image. diff --git a/.storkit/work/6_archived/409_refactor_split_whatsapp_rs_into_focused_modules.md b/.huskies/work/6_archived/409_refactor_split_whatsapp_rs_into_focused_modules.md similarity index 98% rename from .storkit/work/6_archived/409_refactor_split_whatsapp_rs_into_focused_modules.md rename to .huskies/work/6_archived/409_refactor_split_whatsapp_rs_into_focused_modules.md index 9024d3d5..a98a5586 100644 --- a/.storkit/work/6_archived/409_refactor_split_whatsapp_rs_into_focused_modules.md +++ b/.huskies/work/6_archived/409_refactor_split_whatsapp_rs_into_focused_modules.md @@ -31,7 +31,7 @@ whatsapp.rs is 2000+ lines making it expensive for agents to navigate and edit. ## Test Results - + ### Unit Tests (28 passed, 0 failed) diff --git a/.storkit/work/6_archived/40_story_mcp_server_obeys_storykit_port.md b/.huskies/work/6_archived/40_story_mcp_server_obeys_storykit_port.md similarity index 100% rename from .storkit/work/6_archived/40_story_mcp_server_obeys_storykit_port.md rename to .huskies/work/6_archived/40_story_mcp_server_obeys_storykit_port.md diff --git a/.storkit/work/6_archived/410_story_loc_bot_command_top_files_by_line_count.md b/.huskies/work/6_archived/410_story_loc_bot_command_top_files_by_line_count.md similarity index 91% rename from .storkit/work/6_archived/410_story_loc_bot_command_top_files_by_line_count.md rename to .huskies/work/6_archived/410_story_loc_bot_command_top_files_by_line_count.md index 48f75bf4..8c4f8403 100644 --- a/.storkit/work/6_archived/410_story_loc_bot_command_top_files_by_line_count.md +++ b/.huskies/work/6_archived/410_story_loc_bot_command_top_files_by_line_count.md @@ -11,7 +11,7 @@ As a developer, I want to send `loc` to the bot and see the top files by line co ## Acceptance Criteria - [ ] loc command is registered in chat/commands/mod.rs and appears in help output -- [ ] `loc` returns the top 10 source files by line count (excluding generated files, node_modules, target/, .storkit/worktrees/) +- [ ] `loc` returns the top 10 source files by line count (excluding generated files, node_modules, target/, .huskies/worktrees/) - [ ] `loc 5` returns the top 5 files - [ ] `loc 20` returns the top 20 files - [ ] Output includes file path, line count, and rank diff --git a/.storkit/work/6_archived/413_refactor_split_slack_rs_into_focused_modules.md b/.huskies/work/6_archived/413_refactor_split_slack_rs_into_focused_modules.md similarity index 100% rename from .storkit/work/6_archived/413_refactor_split_slack_rs_into_focused_modules.md rename to .huskies/work/6_archived/413_refactor_split_slack_rs_into_focused_modules.md diff --git a/.storkit/work/6_archived/414_story_loc_command_filters_out_known_huge_files.md b/.huskies/work/6_archived/414_story_loc_command_filters_out_known_huge_files.md similarity index 100% rename from .storkit/work/6_archived/414_story_loc_command_filters_out_known_huge_files.md rename to .huskies/work/6_archived/414_story_loc_command_filters_out_known_huge_files.md diff --git a/.storkit/work/6_archived/415_refactor_split_agents_pool_mod_rs_into_submodules.md b/.huskies/work/6_archived/415_refactor_split_agents_pool_mod_rs_into_submodules.md similarity index 100% rename from .storkit/work/6_archived/415_refactor_split_agents_pool_mod_rs_into_submodules.md rename to .huskies/work/6_archived/415_refactor_split_agents_pool_mod_rs_into_submodules.md diff --git a/.storkit/work/6_archived/416_refactor_split_io_fs_rs_into_submodules.md b/.huskies/work/6_archived/416_refactor_split_io_fs_rs_into_submodules.md similarity index 100% rename from .storkit/work/6_archived/416_refactor_split_io_fs_rs_into_submodules.md rename to .huskies/work/6_archived/416_refactor_split_io_fs_rs_into_submodules.md diff --git a/.storkit/work/6_archived/417_refactor_split_matrix_bot_rs_into_focused_modules.md b/.huskies/work/6_archived/417_refactor_split_matrix_bot_rs_into_focused_modules.md similarity index 100% rename from .storkit/work/6_archived/417_refactor_split_matrix_bot_rs_into_focused_modules.md rename to .huskies/work/6_archived/417_refactor_split_matrix_bot_rs_into_focused_modules.md diff --git a/.storkit/work/6_archived/418_refactor_split_pool_auto_assign_rs_into_submodules.md b/.huskies/work/6_archived/418_refactor_split_pool_auto_assign_rs_into_submodules.md similarity index 100% rename from .storkit/work/6_archived/418_refactor_split_pool_auto_assign_rs_into_submodules.md rename to .huskies/work/6_archived/418_refactor_split_pool_auto_assign_rs_into_submodules.md diff --git a/.storkit/work/6_archived/419_bug_matrix_bot_crashes_on_transient_network_error_instead_of_retrying.md b/.huskies/work/6_archived/419_bug_matrix_bot_crashes_on_transient_network_error_instead_of_retrying.md similarity index 95% rename from .storkit/work/6_archived/419_bug_matrix_bot_crashes_on_transient_network_error_instead_of_retrying.md rename to .huskies/work/6_archived/419_bug_matrix_bot_crashes_on_transient_network_error_instead_of_retrying.md index 9a5deb41..b87ac81a 100644 --- a/.storkit/work/6_archived/419_bug_matrix_bot_crashes_on_transient_network_error_instead_of_retrying.md +++ b/.huskies/work/6_archived/419_bug_matrix_bot_crashes_on_transient_network_error_instead_of_retrying.md @@ -10,7 +10,7 @@ The Matrix bot treats a transient sync error as fatal and stops entirely. A sing ## How to Reproduce -1. Run storkit with Matrix bot enabled\n2. Homeserver becomes temporarily unreachable (network blip, DNS hiccup, server restart)\n3. Bot hits sync error and crashes +1. Run huskies with Matrix bot enabled\n2. Homeserver becomes temporarily unreachable (network blip, DNS hiccup, server restart)\n3. Bot hits sync error and crashes ## Actual Result diff --git a/.storkit/work/6_archived/41_story_agent_completion_notification_via_mcp.md b/.huskies/work/6_archived/41_story_agent_completion_notification_via_mcp.md similarity index 100% rename from .storkit/work/6_archived/41_story_agent_completion_notification_via_mcp.md rename to .huskies/work/6_archived/41_story_agent_completion_notification_via_mcp.md diff --git a/.storkit/work/6_archived/420_story_loc_for_a_specified_file_bot_command_and_web_ui_slash_command.md b/.huskies/work/6_archived/420_story_loc_for_a_specified_file_bot_command_and_web_ui_slash_command.md similarity index 100% rename from .storkit/work/6_archived/420_story_loc_for_a_specified_file_bot_command_and_web_ui_slash_command.md rename to .huskies/work/6_archived/420_story_loc_for_a_specified_file_bot_command_and_web_ui_slash_command.md diff --git a/.storkit/work/6_archived/421_story_timer_command_for_deferred_agent_start.md b/.huskies/work/6_archived/421_story_timer_command_for_deferred_agent_start.md similarity index 93% rename from .storkit/work/6_archived/421_story_timer_command_for_deferred_agent_start.md rename to .huskies/work/6_archived/421_story_timer_command_for_deferred_agent_start.md index b6281a34..79be807e 100644 --- a/.storkit/work/6_archived/421_story_timer_command_for_deferred_agent_start.md +++ b/.huskies/work/6_archived/421_story_timer_command_for_deferred_agent_start.md @@ -13,7 +13,7 @@ As a ..., I want ..., so that ... - [ ] Bot command `timer ` schedules a one-shot deferred start for the given story at the next occurrence of that time (server-local timezone) - [ ] Bot command `timer list` shows all pending timers with story ID and scheduled time - [ ] Bot command `timer cancel ` removes the pending timer for that story -- [ ] Timers are persisted to .storkit/timers.json so they survive server restarts +- [ ] Timers are persisted to .huskies/timers.json so they survive server restarts - [ ] A 30s tick loop (tokio task, same pattern as watchdog) checks for due timers and calls start_agent when triggered - [ ] When a timer fires, the story must already be in current — timer does not move stories between stages - [ ] Fired timers are removed after execution (one-shot, not recurring) diff --git a/.storkit/work/6_archived/422_story_unblock_command_to_reset_blocked_stories.md b/.huskies/work/6_archived/422_story_unblock_command_to_reset_blocked_stories.md similarity index 100% rename from .storkit/work/6_archived/422_story_unblock_command_to_reset_blocked_stories.md rename to .huskies/work/6_archived/422_story_unblock_command_to_reset_blocked_stories.md diff --git a/.storkit/work/6_archived/423_story_auto_schedule_timer_on_rate_limit_to_resume_after_reset.md b/.huskies/work/6_archived/423_story_auto_schedule_timer_on_rate_limit_to_resume_after_reset.md similarity index 100% rename from .storkit/work/6_archived/423_story_auto_schedule_timer_on_rate_limit_to_resume_after_reset.md rename to .huskies/work/6_archived/423_story_auto_schedule_timer_on_rate_limit_to_resume_after_reset.md diff --git a/.storkit/work/6_archived/424_story_rate_limit_traffic_light_status_and_hard_block_alerts.md b/.huskies/work/6_archived/424_story_rate_limit_traffic_light_status_and_hard_block_alerts.md similarity index 100% rename from .storkit/work/6_archived/424_story_rate_limit_traffic_light_status_and_hard_block_alerts.md rename to .huskies/work/6_archived/424_story_rate_limit_traffic_light_status_and_hard_block_alerts.md diff --git a/.storkit/work/6_archived/425_story_chat_notification_when_a_story_blocks_with_reason.md b/.huskies/work/6_archived/425_story_chat_notification_when_a_story_blocks_with_reason.md similarity index 100% rename from .storkit/work/6_archived/425_story_chat_notification_when_a_story_blocks_with_reason.md rename to .huskies/work/6_archived/425_story_chat_notification_when_a_story_blocks_with_reason.md diff --git a/.storkit/work/6_archived/426_bug_mergemaster_pipeline_marks_story_done_without_verifying_code_landed_on_master.md b/.huskies/work/6_archived/426_bug_mergemaster_pipeline_marks_story_done_without_verifying_code_landed_on_master.md similarity index 96% rename from .storkit/work/6_archived/426_bug_mergemaster_pipeline_marks_story_done_without_verifying_code_landed_on_master.md rename to .huskies/work/6_archived/426_bug_mergemaster_pipeline_marks_story_done_without_verifying_code_landed_on_master.md index 0c0eb1ae..22508c51 100644 --- a/.storkit/work/6_archived/426_bug_mergemaster_pipeline_marks_story_done_without_verifying_code_landed_on_master.md +++ b/.huskies/work/6_archived/426_bug_mergemaster_pipeline_marks_story_done_without_verifying_code_landed_on_master.md @@ -11,7 +11,7 @@ The mergemaster pipeline can mark a story as done even when the feature code nev ## How to Reproduce -Observed on stories 422 and 403. For 422: mergemaster created merge-queue branch, resolved 2 conflicts in chat/commands/mod.rs and http/mcp/mod.rs, passed quality gates, created merge-queue commit cb2ef6b (4 files, 333 insertions including unblock.rs). But the done commit on master (05db012) only moves the story file — zero code changes. There is no 'storkit: merge 422' commit on master at all. The feature branch (db3157f) still has the code but it was never cherry-picked onto master. +Observed on stories 422 and 403. For 422: mergemaster created merge-queue branch, resolved 2 conflicts in chat/commands/mod.rs and http/mcp/mod.rs, passed quality gates, created merge-queue commit cb2ef6b (4 files, 333 insertions including unblock.rs). But the done commit on master (05db012) only moves the story file — zero code changes. There is no 'huskies: merge 422' commit on master at all. The feature branch (db3157f) still has the code but it was never cherry-picked onto master. ## Manual Merge Notes @@ -53,7 +53,7 @@ Pipeline should verify that the cherry-pick produced a merge commit on master be The code path is: `merge.rs::run_squash_merge` → `pipeline/merge.rs::start_merge_agent_work` → `lifecycle.rs::move_story_to_archived`. -`run_squash_merge` (merge.rs:354) cherry-picks the merge-queue commit onto `project_root` and checks `cp.status.success()`. If it returns `success: true`, `start_merge_agent_work` (pipeline/merge.rs:106) immediately calls `move_story_to_archived`, which moves the story file to `5_done/`. The watcher then commits "storkit: done". +`run_squash_merge` (merge.rs:354) cherry-picks the merge-queue commit onto `project_root` and checks `cp.status.success()`. If it returns `success: true`, `start_merge_agent_work` (pipeline/merge.rs:106) immediately calls `move_story_to_archived`, which moves the story file to `5_done/`. The watcher then commits "huskies: done". The gap: between the cherry-pick returning success and the story moving to done, nobody verifies the cherry-pick actually produced a code commit on master. Possible failure modes: @@ -64,7 +64,7 @@ The gap: between the cherry-pick returning success and the story moving to done, **Fix:** After the cherry-pick in `run_squash_merge` succeeds (line 384), before returning `success: true`: 1. Verify `project_root` is on master: `git rev-parse --abbrev-ref HEAD` must equal the base branch -2. Verify the HEAD commit on master contains the expected merge message (e.g. matches `storkit: merge `) or has a non-empty diff +2. Verify the HEAD commit on master contains the expected merge message (e.g. matches `huskies: merge `) or has a non-empty diff 3. If either check fails, abort the cherry-pick and return `success: false` This keeps the fix entirely within `run_squash_merge` — no changes needed to the pipeline advance or lifecycle code. diff --git a/.storkit/work/6_archived/427_story_server_side_text_normalization_for_chat_message_line_breaks.md b/.huskies/work/6_archived/427_story_server_side_text_normalization_for_chat_message_line_breaks.md similarity index 100% rename from .storkit/work/6_archived/427_story_server_side_text_normalization_for_chat_message_line_breaks.md rename to .huskies/work/6_archived/427_story_server_side_text_normalization_for_chat_message_line_breaks.md diff --git a/.storkit/work/6_archived/428_refactor_split_pool_pipeline_rs_into_submodules.md b/.huskies/work/6_archived/428_refactor_split_pool_pipeline_rs_into_submodules.md similarity index 100% rename from .storkit/work/6_archived/428_refactor_split_pool_pipeline_rs_into_submodules.md rename to .huskies/work/6_archived/428_refactor_split_pool_pipeline_rs_into_submodules.md diff --git a/.storkit/work/6_archived/429_story_interactive_project_setup_wizard_for_new_storkit_projects.md b/.huskies/work/6_archived/429_story_interactive_project_setup_wizard_for_new_storkit_projects.md similarity index 69% rename from .storkit/work/6_archived/429_story_interactive_project_setup_wizard_for_new_storkit_projects.md rename to .huskies/work/6_archived/429_story_interactive_project_setup_wizard_for_new_storkit_projects.md index c92f9b7c..1767153e 100644 --- a/.storkit/work/6_archived/429_story_interactive_project_setup_wizard_for_new_storkit_projects.md +++ b/.huskies/work/6_archived/429_story_interactive_project_setup_wizard_for_new_storkit_projects.md @@ -1,26 +1,26 @@ --- -name: "Interactive project setup wizard for new storkit projects" +name: "Interactive project setup wizard for new huskies projects" agent: coder-opus --- -# Story 429: Interactive project setup wizard for new storkit projects +# Story 429: Interactive project setup wizard for new huskies projects ## User Story -As a developer adopting storkit on an existing project, I want a guided setup process that scaffolds the .storkit directory and has an agent generate project-specific configuration files, so that I can get up and running without manually writing specs and scripts. +As a developer adopting huskies on an existing project, I want a guided setup process that scaffolds the .huskies directory and has an agent generate project-specific configuration files, so that I can get up and running without manually writing specs and scripts. ## Acceptance Criteria -- [ ] storkit init scaffolds .storkit/ directory structure, project.toml, and .mcp.json without clobbering any existing files (especially CLAUDE.md) +- [ ] huskies init scaffolds .huskies/ directory structure, project.toml, and .mcp.json without clobbering any existing files (especially CLAUDE.md) - [ ] Setup wizard tracks progress through ordered steps, resumable if interrupted -- [ ] Step 1: scaffold .storkit/ directory structure and project.toml +- [ ] Step 1: scaffold .huskies/ directory structure and project.toml - [ ] Step 2: agent reads codebase and generates specs/00_CONTEXT.md, user confirms or requests revision - [ ] Step 3: agent reads tech stack and generates specs/tech/STACK.md, user confirms or requests revision - [ ] Step 4: agent creates script/test that runs the project's actual test suite, user runs it to verify, then confirms - [ ] Step 5: agent creates script/release tailored to the project's deployment, user confirms - [ ] Step 6: agent creates script/test_coverage if the stack supports it, user confirms - [ ] Each step gates on user confirmation before advancing to the next -- [ ] Existing CLAUDE.md is preserved — storkit appends its content or leaves it untouched +- [ ] Existing CLAUDE.md is preserved — huskies appends its content or leaves it untouched ## Out of Scope diff --git a/.storkit/work/6_archived/42_story_deterministic_worktree_management_via_rest_mcp_api.md b/.huskies/work/6_archived/42_story_deterministic_worktree_management_via_rest_mcp_api.md similarity index 100% rename from .storkit/work/6_archived/42_story_deterministic_worktree_management_via_rest_mcp_api.md rename to .huskies/work/6_archived/42_story_deterministic_worktree_management_via_rest_mcp_api.md diff --git a/.storkit/work/6_archived/430_bug_status_command_traffic_light_dots_not_coloured_in_matrix.md b/.huskies/work/6_archived/430_bug_status_command_traffic_light_dots_not_coloured_in_matrix.md similarity index 100% rename from .storkit/work/6_archived/430_bug_status_command_traffic_light_dots_not_coloured_in_matrix.md rename to .huskies/work/6_archived/430_bug_status_command_traffic_light_dots_not_coloured_in_matrix.md diff --git a/.storkit/work/6_archived/431_story_qa_agent_reviews_code_changes_against_acceptance_criteria.md b/.huskies/work/6_archived/431_story_qa_agent_reviews_code_changes_against_acceptance_criteria.md similarity index 100% rename from .storkit/work/6_archived/431_story_qa_agent_reviews_code_changes_against_acceptance_criteria.md rename to .huskies/work/6_archived/431_story_qa_agent_reviews_code_changes_against_acceptance_criteria.md diff --git a/.storkit/work/6_archived/432_story_complete_setup_wizard_with_mcp_tools_and_agent_driven_file_generation.md b/.huskies/work/6_archived/432_story_complete_setup_wizard_with_mcp_tools_and_agent_driven_file_generation.md similarity index 95% rename from .storkit/work/6_archived/432_story_complete_setup_wizard_with_mcp_tools_and_agent_driven_file_generation.md rename to .huskies/work/6_archived/432_story_complete_setup_wizard_with_mcp_tools_and_agent_driven_file_generation.md index c2cc639d..086d4e56 100644 --- a/.storkit/work/6_archived/432_story_complete_setup_wizard_with_mcp_tools_and_agent_driven_file_generation.md +++ b/.huskies/work/6_archived/432_story_complete_setup_wizard_with_mcp_tools_and_agent_driven_file_generation.md @@ -7,7 +7,7 @@ agent: "coder-opus" ## User Story -As a developer running storkit init on a new project, I want the setup wizard to walk me through each step interactively — generating files, letting me review them, and confirming before moving on — so that my project is correctly configured without manual file editing. +As a developer running huskies init on a new project, I want the setup wizard to walk me through each step interactively — generating files, letting me review them, and confirming before moving on — so that my project is correctly configured without manual file editing. ## Acceptance Criteria diff --git a/.storkit/work/6_archived/433_story_setup_wizard_interviews_user_on_bare_projects_with_no_existing_code.md b/.huskies/work/6_archived/433_story_setup_wizard_interviews_user_on_bare_projects_with_no_existing_code.md similarity index 100% rename from .storkit/work/6_archived/433_story_setup_wizard_interviews_user_on_bare_projects_with_no_existing_code.md rename to .huskies/work/6_archived/433_story_setup_wizard_interviews_user_on_bare_projects_with_no_existing_code.md diff --git a/.storkit/work/6_archived/434_story_wizard_auto_checks_completion_on_first_conversation.md b/.huskies/work/6_archived/434_story_wizard_auto_checks_completion_on_first_conversation.md similarity index 92% rename from .storkit/work/6_archived/434_story_wizard_auto_checks_completion_on_first_conversation.md rename to .huskies/work/6_archived/434_story_wizard_auto_checks_completion_on_first_conversation.md index 7e42561e..d5f8dc7a 100644 --- a/.storkit/work/6_archived/434_story_wizard_auto_checks_completion_on_first_conversation.md +++ b/.huskies/work/6_archived/434_story_wizard_auto_checks_completion_on_first_conversation.md @@ -6,7 +6,7 @@ name: "Wizard auto-checks completion on first conversation" ## User Story -As a developer opening Claude Code on a storkit project for the first time, I want the wizard to automatically check if setup is complete and prompt me through remaining steps, so I don't have to know to ask for it. +As a developer opening Claude Code on a huskies project for the first time, I want the wizard to automatically check if setup is complete and prompt me through remaining steps, so I don't have to know to ask for it. ## Acceptance Criteria diff --git a/.storkit/work/6_archived/437_bug_strip_prefix_ci_panics_on_multi_byte_utf_8_input.md b/.huskies/work/6_archived/437_bug_strip_prefix_ci_panics_on_multi_byte_utf_8_input.md similarity index 94% rename from .storkit/work/6_archived/437_bug_strip_prefix_ci_panics_on_multi_byte_utf_8_input.md rename to .huskies/work/6_archived/437_bug_strip_prefix_ci_panics_on_multi_byte_utf_8_input.md index 4a8e51ef..eb56a88c 100644 --- a/.storkit/work/6_archived/437_bug_strip_prefix_ci_panics_on_multi_byte_utf_8_input.md +++ b/.huskies/work/6_archived/437_bug_strip_prefix_ci_panics_on_multi_byte_utf_8_input.md @@ -10,7 +10,7 @@ The `strip_prefix_ci` function in `server/src/chat/transport/matrix/assign.rs` s ## How to Reproduce -Send a Matrix message to the bot that starts with a multi-byte UTF-8 character (e.g. `⏺ storkit - wizard_confirm`) where the bot name byte length falls inside a multi-byte character. +Send a Matrix message to the bot that starts with a multi-byte UTF-8 character (e.g. `⏺ huskies - wizard_confirm`) where the bot name byte length falls inside a multi-byte character. ## Actual Result diff --git a/.storkit/work/6_archived/438_story_slash_command_autocomplete_in_web_ui_text_input.md b/.huskies/work/6_archived/438_story_slash_command_autocomplete_in_web_ui_text_input.md similarity index 100% rename from .storkit/work/6_archived/438_story_slash_command_autocomplete_in_web_ui_text_input.md rename to .huskies/work/6_archived/438_story_slash_command_autocomplete_in_web_ui_text_input.md diff --git a/.storkit/work/6_archived/439_refactor_unify_story_stuck_states_into_a_single_status_field.md b/.huskies/work/6_archived/439_refactor_unify_story_stuck_states_into_a_single_status_field.md similarity index 100% rename from .storkit/work/6_archived/439_refactor_unify_story_stuck_states_into_a_single_status_field.md rename to .huskies/work/6_archived/439_refactor_unify_story_stuck_states_into_a_single_status_field.md diff --git a/.storkit/work/6_archived/43_story_unified_chat_ui_for_claude_code_and_regular_chat.md b/.huskies/work/6_archived/43_story_unified_chat_ui_for_claude_code_and_regular_chat.md similarity index 100% rename from .storkit/work/6_archived/43_story_unified_chat_ui_for_claude_code_and_regular_chat.md rename to .huskies/work/6_archived/43_story_unified_chat_ui_for_claude_code_and_regular_chat.md diff --git a/.storkit/work/6_archived/440_refactor_consolidate_is_permission_approval_into_chat_util.md b/.huskies/work/6_archived/440_refactor_consolidate_is_permission_approval_into_chat_util.md similarity index 100% rename from .storkit/work/6_archived/440_refactor_consolidate_is_permission_approval_into_chat_util.md rename to .huskies/work/6_archived/440_refactor_consolidate_is_permission_approval_into_chat_util.md diff --git a/.storkit/work/6_archived/441_refactor_deduplicate_get_project_root_wrappers_in_io_modules.md b/.huskies/work/6_archived/441_refactor_deduplicate_get_project_root_wrappers_in_io_modules.md similarity index 100% rename from .storkit/work/6_archived/441_refactor_deduplicate_get_project_root_wrappers_in_io_modules.md rename to .huskies/work/6_archived/441_refactor_deduplicate_get_project_root_wrappers_in_io_modules.md diff --git a/.storkit/work/6_archived/442_refactor_deduplicate_stage_display_name_into_shared_module.md b/.huskies/work/6_archived/442_refactor_deduplicate_stage_display_name_into_shared_module.md similarity index 100% rename from .storkit/work/6_archived/442_refactor_deduplicate_stage_display_name_into_shared_module.md rename to .huskies/work/6_archived/442_refactor_deduplicate_stage_display_name_into_shared_module.md diff --git a/.storkit/work/6_archived/443_refactor_extract_shared_find_story_name_from_commands.md b/.huskies/work/6_archived/443_refactor_extract_shared_find_story_name_from_commands.md similarity index 100% rename from .storkit/work/6_archived/443_refactor_extract_shared_find_story_name_from_commands.md rename to .huskies/work/6_archived/443_refactor_extract_shared_find_story_name_from_commands.md diff --git a/.storkit/work/6_archived/444_refactor_extract_shared_test_helpers_test_ctx_write_story_file_make_api.md b/.huskies/work/6_archived/444_refactor_extract_shared_test_helpers_test_ctx_write_story_file_make_api.md similarity index 100% rename from .storkit/work/6_archived/444_refactor_extract_shared_test_helpers_test_ctx_write_story_file_make_api.md rename to .huskies/work/6_archived/444_refactor_extract_shared_test_helpers_test_ctx_write_story_file_make_api.md diff --git a/.storkit/work/6_archived/445_bug_rate_limited_mergemaster_exits_advance_stories_to_done_without_merging.md b/.huskies/work/6_archived/445_bug_rate_limited_mergemaster_exits_advance_stories_to_done_without_merging.md similarity index 100% rename from .storkit/work/6_archived/445_bug_rate_limited_mergemaster_exits_advance_stories_to_done_without_merging.md rename to .huskies/work/6_archived/445_bug_rate_limited_mergemaster_exits_advance_stories_to_done_without_merging.md diff --git a/.storkit/work/6_archived/446_story_oauth_login_button_in_web_ui.md b/.huskies/work/6_archived/446_story_oauth_login_button_in_web_ui.md similarity index 90% rename from .storkit/work/6_archived/446_story_oauth_login_button_in_web_ui.md rename to .huskies/work/6_archived/446_story_oauth_login_button_in_web_ui.md index 37dd327d..139d0bfb 100644 --- a/.storkit/work/6_archived/446_story_oauth_login_button_in_web_ui.md +++ b/.huskies/work/6_archived/446_story_oauth_login_button_in_web_ui.md @@ -6,7 +6,7 @@ name: "OAuth login button in web UI" ## User Story -As a user of the storkit web UI, I want a login button that triggers the Anthropic OAuth flow, so that I can authenticate without manually navigating to /oauth/authorize. +As a user of the huskies web UI, I want a login button that triggers the Anthropic OAuth flow, so that I can authenticate without manually navigating to /oauth/authorize. ## Acceptance Criteria diff --git a/.storkit/work/6_archived/447_bug_element_tab_completion_display_name_breaks_bot_command_matching.md b/.huskies/work/6_archived/447_bug_element_tab_completion_display_name_breaks_bot_command_matching.md similarity index 100% rename from .storkit/work/6_archived/447_bug_element_tab_completion_display_name_breaks_bot_command_matching.md rename to .huskies/work/6_archived/447_bug_element_tab_completion_display_name_breaks_bot_command_matching.md diff --git a/.storkit/work/6_archived/448_story_send_oauth_login_link_via_chat_when_credentials_are_missing.md b/.huskies/work/6_archived/448_story_send_oauth_login_link_via_chat_when_credentials_are_missing.md similarity index 78% rename from .storkit/work/6_archived/448_story_send_oauth_login_link_via_chat_when_credentials_are_missing.md rename to .huskies/work/6_archived/448_story_send_oauth_login_link_via_chat_when_credentials_are_missing.md index ab47b2fb..27733a5b 100644 --- a/.storkit/work/6_archived/448_story_send_oauth_login_link_via_chat_when_credentials_are_missing.md +++ b/.huskies/work/6_archived/448_story_send_oauth_login_link_via_chat_when_credentials_are_missing.md @@ -6,13 +6,13 @@ name: "Send OAuth login link via chat when credentials are missing" ## User Story -As a storkit user on Matrix or WhatsApp, I want the bot to send me a clickable OAuth authorize link when credentials are missing or expired, so that I can authenticate without terminal access or manually constructing the URL. +As a huskies user on Matrix or WhatsApp, I want the bot to send me a clickable OAuth authorize link when credentials are missing or expired, so that I can authenticate without terminal access or manually constructing the URL. ## Acceptance Criteria -- [ ] When storkit detects missing or expired credentials during a chat interaction, it sends the user a clickable /oauth/authorize link +- [ ] When huskies detects missing or expired credentials during a chat interaction, it sends the user a clickable /oauth/authorize link - [ ] Works on Matrix and WhatsApp transports -- [ ] After successful OAuth callback, the user can immediately resume chatting without restarting storkit +- [ ] After successful OAuth callback, the user can immediately resume chatting without restarting huskies - [ ] If credentials are already valid, no login link is sent ## Out of Scope diff --git a/.storkit/work/6_archived/449_bug_oauth_callback_url_ignores_port_cli_flag.md b/.huskies/work/6_archived/449_bug_oauth_callback_url_ignores_port_cli_flag.md similarity index 90% rename from .storkit/work/6_archived/449_bug_oauth_callback_url_ignores_port_cli_flag.md rename to .huskies/work/6_archived/449_bug_oauth_callback_url_ignores_port_cli_flag.md index 63b1a9ba..ae027466 100644 --- a/.storkit/work/6_archived/449_bug_oauth_callback_url_ignores_port_cli_flag.md +++ b/.huskies/work/6_archived/449_bug_oauth_callback_url_ignores_port_cli_flag.md @@ -10,11 +10,11 @@ OAuthState is initialized with `resolve_port()` (reads STORKIT_PORT env var, def ## How to Reproduce -Start storkit with `--port 4000` (without setting STORKIT_PORT env var). Click the OAuth login button in the web UI. Authenticate with Anthropic. The callback redirect goes to localhost:3001 instead of localhost:4000. +Start huskies with `--port 4000` (without setting STORKIT_PORT env var). Click the OAuth login button in the web UI. Authenticate with Anthropic. The callback redirect goes to localhost:3001 instead of localhost:4000. ## Actual Result -Callback hits port 3001 (or wrong port). If a different storkit is running there, it returns "Invalid State". If nothing is running there, the page fails to load. +Callback hits port 3001 (or wrong port). If a different huskies is running there, it returns "Invalid State". If nothing is running there, the page fails to load. ## Expected Result diff --git a/.storkit/work/6_archived/44_story_agent_completion_report_via_mcp.md b/.huskies/work/6_archived/44_story_agent_completion_report_via_mcp.md similarity index 100% rename from .storkit/work/6_archived/44_story_agent_completion_report_via_mcp.md rename to .huskies/work/6_archived/44_story_agent_completion_report_via_mcp.md diff --git a/.storkit/work/6_archived/450_bug_web_ui_silently_swallows_chat_errors_including_oauth_login_link.md b/.huskies/work/6_archived/450_bug_web_ui_silently_swallows_chat_errors_including_oauth_login_link.md similarity index 100% rename from .storkit/work/6_archived/450_bug_web_ui_silently_swallows_chat_errors_including_oauth_login_link.md rename to .huskies/work/6_archived/450_bug_web_ui_silently_swallows_chat_errors_including_oauth_login_link.md diff --git a/.storkit/work/6_archived/451_bug_chat_test_tsx_help_test_expects_removed_overlay_behavior.md b/.huskies/work/6_archived/451_bug_chat_test_tsx_help_test_expects_removed_overlay_behavior.md similarity index 100% rename from .storkit/work/6_archived/451_bug_chat_test_tsx_help_test_expects_removed_overlay_behavior.md rename to .huskies/work/6_archived/451_bug_chat_test_tsx_help_test_expects_removed_overlay_behavior.md diff --git a/.storkit/work/6_archived/452_bug_claude_code_pty_crashes_with_fatal_runtime_error_on_agent_restart.md b/.huskies/work/6_archived/452_bug_claude_code_pty_crashes_with_fatal_runtime_error_on_agent_restart.md similarity index 89% rename from .storkit/work/6_archived/452_bug_claude_code_pty_crashes_with_fatal_runtime_error_on_agent_restart.md rename to .huskies/work/6_archived/452_bug_claude_code_pty_crashes_with_fatal_runtime_error_on_agent_restart.md index 18498682..31ad8538 100644 --- a/.storkit/work/6_archived/452_bug_claude_code_pty_crashes_with_fatal_runtime_error_on_agent_restart.md +++ b/.huskies/work/6_archived/452_bug_claude_code_pty_crashes_with_fatal_runtime_error_on_agent_restart.md @@ -6,16 +6,16 @@ name: "Zombie process accumulation from unrereaped child processes" ## Description -Storkit accumulates zombie processes over time from unrereaped child and grandchild processes. Observed 101 zombies in Docker container, 27 on macOS host. Breakdown: 51 esbuild, 36 echo, 5 claude, 5 sh, 2 bash, 1 cargo. +Huskies accumulates zombie processes over time from unrereaped child and grandchild processes. Observed 101 zombies in Docker container, 27 on macOS host. Breakdown: 51 esbuild, 36 echo, 5 claude, 5 sh, 2 bash, 1 cargo. -Root cause: storkit does not reap orphaned grandchild processes. The zombies are mostly grandchildren (`esbuild`, `echo`, `sh`, `cargo`) spawned by `npm run build`, `cargo test`, etc. during worktree setup and gate checks. This happens both natively (observed 27 zombies on macOS host) and in Docker containers. When the intermediate parent exits, these grandchildren get reparented to storkit (or PID 1 in Docker) and become zombies because nobody calls `waitpid` for them. +Root cause: huskies does not reap orphaned grandchild processes. The zombies are mostly grandchildren (`esbuild`, `echo`, `sh`, `cargo`) spawned by `npm run build`, `cargo test`, etc. during worktree setup and gate checks. This happens both natively (observed 27 zombies on macOS host) and in Docker containers. When the intermediate parent exits, these grandchildren get reparented to huskies (or PID 1 in Docker) and become zombies because nobody calls `waitpid` for them. **Already fixed:** - `docker-compose.yml` now has `init: true` which uses tini as PID 1 in Docker — this handles zombie reaping inside containers - `llm/providers/claude_code.rs` now has `child.wait()` after `child.kill()` in all code paths, and the reader thread is joined before returning - `agents/pty.rs` reader thread is now joined before returning -**Remaining:** Storkit running natively (e.g. on macOS) still accumulates zombie grandchildren because there is no tini. The fix is to add a background reaper thread that periodically calls `waitpid(-1, WNOHANG)` in a loop to clean up any orphaned children. This should be spawned early in `main()` on Unix platforms. Example: +**Remaining:** Huskies running natively (e.g. on macOS) still accumulates zombie grandchildren because there is no tini. The fix is to add a background reaper thread that periodically calls `waitpid(-1, WNOHANG)` in a loop to clean up any orphaned children. This should be spawned early in `main()` on Unix platforms. Example: ```rust #[cfg(unix)] diff --git a/.storkit/work/6_archived/453_bug_agent_pty_crashes_with_fatal_runtime_error_on_restart_after_gate_failure.md b/.huskies/work/6_archived/453_bug_agent_pty_crashes_with_fatal_runtime_error_on_restart_after_gate_failure.md similarity index 92% rename from .storkit/work/6_archived/453_bug_agent_pty_crashes_with_fatal_runtime_error_on_restart_after_gate_failure.md rename to .huskies/work/6_archived/453_bug_agent_pty_crashes_with_fatal_runtime_error_on_restart_after_gate_failure.md index baf114de..e1efaf15 100644 --- a/.storkit/work/6_archived/453_bug_agent_pty_crashes_with_fatal_runtime_error_on_restart_after_gate_failure.md +++ b/.huskies/work/6_archived/453_bug_agent_pty_crashes_with_fatal_runtime_error_on_restart_after_gate_failure.md @@ -12,7 +12,7 @@ Key observations: - The crash is **deterministic, not intermittent**: the first PTY spawn in a worktree always works; the second spawn (restart) always crashes - Running `claude -p "hello"` manually in the same worktree works fine (no crash) — the issue is specific to spawning via portable-pty - The worktree is clean (all changes committed) — the agent has nothing to do but fix the gate failure -- The crash is inside the Claude Code binary, not storkit code +- The crash is inside the Claude Code binary, not huskies code - Observed on every story that needed a restart: 329, 400, 420, 438, 446, 449, 450 - Stories that passed gates on the first run were never affected — they never triggered a second spawn @@ -23,14 +23,14 @@ The root cause is unknown. It is NOT caused by zombie process accumulation (that **Timeline:** The crash first appeared on 2026-03-21. Agent logs go back to 2026-02-23 with no instances before that date. Stories that hit it: 329 (Mar 21), 400 (Mar 26), 420 (Mar 28), 438 (Mar 28), 446 (Mar 30), 449 (Mar 31), 450 (Mar 31). **Suspect commits around 2026-03-21:** -- `4344081b` — storkit: merge 343_refactor_abstract_agent_runtime_to_support_non_claude_code_backends (refactored agent runtime layer) -- `c4e45b28` — The great storkit name conversion +- `4344081b` — huskies: merge 343_refactor_abstract_agent_runtime_to_support_non_claude_code_backends (refactored agent runtime layer) +- `c4e45b28` — The great huskies name conversion - Story 359 — Docker security hardening (`cap_drop: ALL`, added back only `SETUID`/`SETGID`) — could affect PTY allocation - Story 329 — Docker/OrbStack evaluation spike (first crash was on this story's mergemaster) **Ruled out:** Docker capability restrictions (cap_drop: ALL) — tested by temporarily removing all cap_drop/security_opt; crash still occurs. -**Evidence of stale PTY fd:** After all agents stopped, storkit (PID 7) was still holding an open fd to `/dev/pts/ptmx` (fd 46). This is a leaked PTY master fd from a previous agent session. The reader thread spawned by `std::thread::spawn` in `pty.rs` is never joined, so the cloned reader fd stays open in the storkit process after the agent exits. +**Evidence of stale PTY fd:** After all agents stopped, huskies (PID 7) was still holding an open fd to `/dev/pts/ptmx` (fd 46). This is a leaked PTY master fd from a previous agent session. The reader thread spawned by `std::thread::spawn` in `pty.rs` is never joined, so the cloned reader fd stays open in the huskies process after the agent exits. Remaining areas to investigate: the unjoined reader thread leaking PTY fds, and whether the leaked fd from the first session interferes with the second PTY allocation. diff --git a/.storkit/work/6_archived/454_story_deduplicate_work_item_display_in_web_ui_story_panel.md b/.huskies/work/6_archived/454_story_deduplicate_work_item_display_in_web_ui_story_panel.md similarity index 100% rename from .storkit/work/6_archived/454_story_deduplicate_work_item_display_in_web_ui_story_panel.md rename to .huskies/work/6_archived/454_story_deduplicate_work_item_display_in_web_ui_story_panel.md diff --git a/.storkit/work/6_archived/456_bug_matrix_bot_ignores_in_room_verification_requests_from_element.md b/.huskies/work/6_archived/456_bug_matrix_bot_ignores_in_room_verification_requests_from_element.md similarity index 97% rename from .storkit/work/6_archived/456_bug_matrix_bot_ignores_in_room_verification_requests_from_element.md rename to .huskies/work/6_archived/456_bug_matrix_bot_ignores_in_room_verification_requests_from_element.md index 9bce55b5..23a1c1bf 100644 --- a/.storkit/work/6_archived/456_bug_matrix_bot_ignores_in_room_verification_requests_from_element.md +++ b/.huskies/work/6_archived/456_bug_matrix_bot_ignores_in_room_verification_requests_from_element.md @@ -10,7 +10,7 @@ The Matrix bot (Sally) only registers a handler for to-device verification event ## How to Reproduce -1. Run the storkit Matrix bot (Sally) in a room with E2EE enabled. 2. In Element, open the room member list, click Sally's device, and press "Start Verification". 3. Watch the bot logs: grep for "verif\|Incoming". +1. Run the huskies Matrix bot (Sally) in a room with E2EE enabled. 2. In Element, open the room member list, click Sally's device, and press "Start Verification". 3. Watch the bot logs: grep for "verif\|Incoming". ## Actual Result diff --git a/.storkit/work/6_archived/457_bug_store_json_created_at_project_root_instead_of_inside_storkit.md b/.huskies/work/6_archived/457_bug_store_json_created_at_project_root_instead_of_inside_storkit.md similarity index 63% rename from .storkit/work/6_archived/457_bug_store_json_created_at_project_root_instead_of_inside_storkit.md rename to .huskies/work/6_archived/457_bug_store_json_created_at_project_root_instead_of_inside_storkit.md index b7d532eb..a0e5ad90 100644 --- a/.storkit/work/6_archived/457_bug_store_json_created_at_project_root_instead_of_inside_storkit.md +++ b/.huskies/work/6_archived/457_bug_store_json_created_at_project_root_instead_of_inside_storkit.md @@ -1,16 +1,16 @@ --- -name: "store.json created at project root instead of inside .storkit/" +name: "store.json created at project root instead of inside .huskies/" --- -# Bug 457: store.json created at project root instead of inside .storkit/ +# Bug 457: store.json created at project root instead of inside .huskies/ ## Description -In main.rs, JsonFileStore is initialised with a hardcoded relative path `PathBuf::from("store.json")`, which creates the file in whatever directory the process was started from (typically the project root). It should live inside `.storkit/` alongside other runtime state files. The scaffold .gitignore also lists `store.json` as a root-level pattern rather than `.storkit/store.json`, and the scaffold comment/entries array in scaffold.rs explicitly lists `store.json` as a root-level file to ignore — both need updating. +In main.rs, JsonFileStore is initialised with a hardcoded relative path `PathBuf::from("store.json")`, which creates the file in whatever directory the process was started from (typically the project root). It should live inside `.huskies/` alongside other runtime state files. The scaffold .gitignore also lists `store.json` as a root-level pattern rather than `.huskies/store.json`, and the scaffold comment/entries array in scaffold.rs explicitly lists `store.json` as a root-level file to ignore — both need updating. ## How to Reproduce -1. Run storkit in any project directory. 2. Observe that store.json is created at the project root rather than inside .storkit/. +1. Run huskies in any project directory. 2. Observe that store.json is created at the project root rather than inside .huskies/. ## Actual Result @@ -18,12 +18,12 @@ store.json is created at the working directory root, polluting the project root ## Expected Result -store.json is created at project_root/.storkit/store.json. The scaffold-generated .gitignore ignores .storkit/store.json. The scaffold comment and entries array in scaffold.rs no longer list store.json as a root-level file. +store.json is created at project_root/.huskies/store.json. The scaffold-generated .gitignore ignores .huskies/store.json. The scaffold comment and entries array in scaffold.rs no longer list store.json as a root-level file. ## Acceptance Criteria -- [ ] main.rs initialises JsonFileStore at project_root.join(".storkit").join("store.json") instead of PathBuf::from("store.json") -- [ ] scaffold.rs .gitignore entries updated: store.json root entry removed, .storkit/store.json added +- [ ] main.rs initialises JsonFileStore at project_root.join(".huskies").join("store.json") instead of PathBuf::from("store.json") +- [ ] scaffold.rs .gitignore entries updated: store.json root entry removed, .huskies/store.json added - [ ] scaffold.rs comment on line ~333 updated to reflect store.json is no longer at the root - [ ] wizard_tools.rs filter for store.json updated to match the new path if needed -- [ ] Existing deployments with a root-level store.json are not broken (storkit migrates or falls back gracefully) +- [ ] Existing deployments with a root-level store.json are not broken (huskies migrates or falls back gracefully) diff --git a/.storkit/work/6_archived/458_story_matrix_bot_ignores_messages_addressed_to_other_bots_in_ambient_mode.md b/.huskies/work/6_archived/458_story_matrix_bot_ignores_messages_addressed_to_other_bots_in_ambient_mode.md similarity index 100% rename from .storkit/work/6_archived/458_story_matrix_bot_ignores_messages_addressed_to_other_bots_in_ambient_mode.md rename to .huskies/work/6_archived/458_story_matrix_bot_ignores_messages_addressed_to_other_bots_in_ambient_mode.md diff --git a/.storkit/work/6_archived/459_bug_matrix_history_json_and_timers_json_missing_from_scaffold_storkit_gitignore.md b/.huskies/work/6_archived/459_bug_matrix_history_json_and_timers_json_missing_from_scaffold_storkit_gitignore.md similarity index 72% rename from .storkit/work/6_archived/459_bug_matrix_history_json_and_timers_json_missing_from_scaffold_storkit_gitignore.md rename to .huskies/work/6_archived/459_bug_matrix_history_json_and_timers_json_missing_from_scaffold_storkit_gitignore.md index 89e6b957..63b8d9cc 100644 --- a/.storkit/work/6_archived/459_bug_matrix_history_json_and_timers_json_missing_from_scaffold_storkit_gitignore.md +++ b/.huskies/work/6_archived/459_bug_matrix_history_json_and_timers_json_missing_from_scaffold_storkit_gitignore.md @@ -1,16 +1,16 @@ --- -name: "matrix_history.json and timers.json missing from scaffold .storkit/.gitignore" +name: "matrix_history.json and timers.json missing from scaffold .huskies/.gitignore" --- -# Bug 459: matrix_history.json and timers.json missing from scaffold .storkit/.gitignore +# Bug 459: matrix_history.json and timers.json missing from scaffold .huskies/.gitignore ## Description -The scaffold's write_story_kit_gitignore function in scaffold.rs does not include matrix_history.json or timers.json in the .storkit/.gitignore entries. Both files are runtime state that should not be committed to git. matrix_device_id and matrix_store/ are already covered, but matrix_history.json (conversation history) and timers.json (timer store) are missing. +The scaffold's write_story_kit_gitignore function in scaffold.rs does not include matrix_history.json or timers.json in the .huskies/.gitignore entries. Both files are runtime state that should not be committed to git. matrix_device_id and matrix_store/ are already covered, but matrix_history.json (conversation history) and timers.json (timer store) are missing. ## How to Reproduce -1. Run storkit scaffold on a new project. 2. Start the Matrix bot. 3. Observe that matrix_history.json and timers.json are created inside .storkit/ but are not gitignored. +1. Run huskies scaffold on a new project. 2. Start the Matrix bot. 3. Observe that matrix_history.json and timers.json are created inside .huskies/ but are not gitignored. ## Actual Result @@ -18,7 +18,7 @@ matrix_history.json and timers.json appear as untracked files in git status. ## Expected Result -Both files are listed in .storkit/.gitignore and do not appear in git status. +Both files are listed in .huskies/.gitignore and do not appear in git status. ## Acceptance Criteria diff --git a/.storkit/work/6_archived/45_story_deterministic_story_lifecycle_management.md b/.huskies/work/6_archived/45_story_deterministic_story_lifecycle_management.md similarity index 100% rename from .storkit/work/6_archived/45_story_deterministic_story_lifecycle_management.md rename to .huskies/work/6_archived/45_story_deterministic_story_lifecycle_management.md diff --git a/.storkit/work/6_archived/460_bug_strip_bot_mention_fails_on_element_markdown_mention_pill_format.md b/.huskies/work/6_archived/460_bug_strip_bot_mention_fails_on_element_markdown_mention_pill_format.md similarity index 100% rename from .storkit/work/6_archived/460_bug_strip_bot_mention_fails_on_element_markdown_mention_pill_format.md rename to .huskies/work/6_archived/460_bug_strip_bot_mention_fails_on_element_markdown_mention_pill_format.md diff --git a/.storkit/work/6_archived/461_bug_strip_bot_mention_fails_on_element_markdown_mention_pill_format.md b/.huskies/work/6_archived/461_bug_strip_bot_mention_fails_on_element_markdown_mention_pill_format.md similarity index 100% rename from .storkit/work/6_archived/461_bug_strip_bot_mention_fails_on_element_markdown_mention_pill_format.md rename to .huskies/work/6_archived/461_bug_strip_bot_mention_fails_on_element_markdown_mention_pill_format.md diff --git a/.storkit/work/6_archived/46_story_deterministic_story_mutations_with_auto_commit.md b/.huskies/work/6_archived/46_story_deterministic_story_mutations_with_auto_commit.md similarity index 97% rename from .storkit/work/6_archived/46_story_deterministic_story_mutations_with_auto_commit.md rename to .huskies/work/6_archived/46_story_deterministic_story_mutations_with_auto_commit.md index e82480a7..29190520 100644 --- a/.storkit/work/6_archived/46_story_deterministic_story_mutations_with_auto_commit.md +++ b/.huskies/work/6_archived/46_story_deterministic_story_mutations_with_auto_commit.md @@ -15,7 +15,7 @@ As a developer running autonomous agents, I want all story file mutations to hap - [ ] `start_agent` auto-commits the move from upcoming/ to current/ on master - [ ] New MCP tool `check_criterion(story_id, criterion_index)` checks off an acceptance criterion and auto-commits to master - [ ] New MCP tool `set_test_plan(story_id, status)` updates the test_plan front matter field and auto-commits to master -- [ ] All auto-commits use deterministic commit messages (e.g. "storkit: accept story 42") +- [ ] All auto-commits use deterministic commit messages (e.g. "huskies: accept story 42") - [ ] Agents never need to edit story markdown files directly — all mutations go through server tools ## Out of Scope diff --git a/.storkit/work/6_archived/48_story_two_column_layout.md b/.huskies/work/6_archived/48_story_two_column_layout.md similarity index 100% rename from .storkit/work/6_archived/48_story_two_column_layout.md rename to .huskies/work/6_archived/48_story_two_column_layout.md diff --git a/.storkit/work/6_archived/49_story_deterministic_bug_lifecycle_management.md b/.huskies/work/6_archived/49_story_deterministic_bug_lifecycle_management.md similarity index 95% rename from .storkit/work/6_archived/49_story_deterministic_bug_lifecycle_management.md rename to .huskies/work/6_archived/49_story_deterministic_bug_lifecycle_management.md index 6ca5a43e..e12ebc75 100644 --- a/.storkit/work/6_archived/49_story_deterministic_bug_lifecycle_management.md +++ b/.huskies/work/6_archived/49_story_deterministic_bug_lifecycle_management.md @@ -15,7 +15,7 @@ As a developer running autonomous agents, I want all bug file mutations to happe - [ ] New MCP tool `list_bugs()` returns all open bugs (files in `.story_kit/bugs/` excluding `archive/`) - [ ] New MCP tool `close_bug(bug_id)` moves a bug from `.story_kit/bugs/` to `.story_kit/bugs/archive/` and auto-commits to master - [ ] `start_agent` supports bug IDs (e.g. `bug-5-description`) — no move needed since bugs don't have upcoming/current -- [ ] All auto-commits use deterministic commit messages (e.g. "storkit: create bug bug-6-fix-foo", "storkit: close bug bug-5") +- [ ] All auto-commits use deterministic commit messages (e.g. "huskies: create bug bug-6-fix-foo", "huskies: close bug bug-5") - [ ] Agents never need to edit bug markdown files directly — all mutations go through server tools ## Out of Scope diff --git a/.storkit/work/6_archived/50_story_unified_current_work_directory.md b/.huskies/work/6_archived/50_story_unified_current_work_directory.md similarity index 100% rename from .storkit/work/6_archived/50_story_unified_current_work_directory.md rename to .huskies/work/6_archived/50_story_unified_current_work_directory.md diff --git a/.storkit/work/6_archived/52_story_mergemaster_agent_role.md b/.huskies/work/6_archived/52_story_mergemaster_agent_role.md similarity index 100% rename from .storkit/work/6_archived/52_story_mergemaster_agent_role.md rename to .huskies/work/6_archived/52_story_mergemaster_agent_role.md diff --git a/.storkit/work/6_archived/53_story_qa_agent_role.md b/.huskies/work/6_archived/53_story_qa_agent_role.md similarity index 100% rename from .storkit/work/6_archived/53_story_qa_agent_role.md rename to .huskies/work/6_archived/53_story_qa_agent_role.md diff --git a/.storkit/work/6_archived/55_story_live_story_panel_updates.md b/.huskies/work/6_archived/55_story_live_story_panel_updates.md similarity index 100% rename from .storkit/work/6_archived/55_story_live_story_panel_updates.md rename to .huskies/work/6_archived/55_story_live_story_panel_updates.md diff --git a/.storkit/work/6_archived/56_story_auto_increment_work_item_ids.md b/.huskies/work/6_archived/56_story_auto_increment_work_item_ids.md similarity index 100% rename from .storkit/work/6_archived/56_story_auto_increment_work_item_ids.md rename to .huskies/work/6_archived/56_story_auto_increment_work_item_ids.md diff --git a/.storkit/work/6_archived/59_story_current_work_panel.md b/.huskies/work/6_archived/59_story_current_work_panel.md similarity index 100% rename from .storkit/work/6_archived/59_story_current_work_panel.md rename to .huskies/work/6_archived/59_story_current_work_panel.md diff --git a/.storkit/work/6_archived/5_bug_fix_collect_coverage_button_error.md b/.huskies/work/6_archived/5_bug_fix_collect_coverage_button_error.md similarity index 100% rename from .storkit/work/6_archived/5_bug_fix_collect_coverage_button_error.md rename to .huskies/work/6_archived/5_bug_fix_collect_coverage_button_error.md diff --git a/.storkit/work/6_archived/60_story_status_based_directory_layout.md b/.huskies/work/6_archived/60_story_status_based_directory_layout.md similarity index 100% rename from .storkit/work/6_archived/60_story_status_based_directory_layout.md rename to .huskies/work/6_archived/60_story_status_based_directory_layout.md diff --git a/.storkit/work/6_archived/61_spike_filesystem_watcher_architecture.md b/.huskies/work/6_archived/61_spike_filesystem_watcher_architecture.md similarity index 93% rename from .storkit/work/6_archived/61_spike_filesystem_watcher_architecture.md rename to .huskies/work/6_archived/61_spike_filesystem_watcher_architecture.md index ad119b34..075d1138 100644 --- a/.storkit/work/6_archived/61_spike_filesystem_watcher_architecture.md +++ b/.huskies/work/6_archived/61_spike_filesystem_watcher_architecture.md @@ -22,7 +22,7 @@ The server is a file mover that commits. Every mutation handler does the same th 1. **`notify` crate** — does it reliably detect renames/moves across subdirectories on macOS and Linux? What events fire for `fs::rename`? 2. **Debouncing** — git operations touch multiple files. What's the right debounce window? Can we batch changes into a single commit? -3. **Deterministic commit messages** — can the watcher infer intent from the move? e.g., file appears in `2_current/` → "storkit: start {story_id}", file appears in `5_archived/` → "storkit: accept {story_id}" +3. **Deterministic commit messages** — can the watcher infer intent from the move? e.g., file appears in `2_current/` → "huskies: start {story_id}", file appears in `5_archived/` → "huskies: accept {story_id}" 4. **Race conditions** — what if the watcher fires while a git commit is in progress? Need a mutex or queue? 5. **What stays in mutation handlers** — do the MCP tools still need validation (e.g., "can't move to 2_current if not in 1_upcoming")? Or is the filesystem the only source of truth? 6. **Worktree interaction** — worktrees share `.git/`, so commits from the watcher in the main repo don't conflict with worktree work @@ -50,7 +50,7 @@ The server is a file mover that commits. Every mutation handler does the same th - **WebSocket integration** (`server/src/http/ws.rs`): Each WebSocket client subscribes to a `broadcast::Sender`. When the watcher flushes a batch, it broadcasts a `WatcherEvent`; the WS handler converts it to `WorkItemChanged` and pushes it to the client. Frontend gets live updates with no polling. -- **`create_story` simplified** (`server/src/http/mcp.rs`): The MCP tool now writes the file and returns — `commit = false`. The watcher picks up the new file in `1_upcoming/` within 300 ms and auto-commits `"storkit: create {story_id}"`. +- **`create_story` simplified** (`server/src/http/mcp.rs`): The MCP tool now writes the file and returns — `commit = false`. The watcher picks up the new file in `1_upcoming/` within 300 ms and auto-commits `"huskies: create {story_id}"`. ### Questions Answered @@ -58,7 +58,7 @@ The server is a file mover that commits. Every mutation handler does the same th 2. **Debouncing**: 300 ms works well in practice. `fs::rename` is atomic and fires a single event. File writes (e.g. editing a story) may fire multiple events; 300 ms collapses them into one commit. Longer windows (500 ms+) could be used if git is slow. -3. **Deterministic commit messages**: Yes — directory name → action mapping is clean. Stage `1_upcoming` → `"storkit: create {item_id}"`, `2_current` → `"storkit: start {item_id}"`, `3_qa` → `"storkit: queue {item_id} for QA"`, `4_merge` → `"storkit: queue {item_id} for merge"`, `5_archived` → `"storkit: accept {item_id}"`. +3. **Deterministic commit messages**: Yes — directory name → action mapping is clean. Stage `1_upcoming` → `"huskies: create {item_id}"`, `2_current` → `"huskies: start {item_id}"`, `3_qa` → `"huskies: queue {item_id} for QA"`, `4_merge` → `"huskies: queue {item_id} for merge"`, `5_archived` → `"huskies: accept {item_id}"`. 4. **Race conditions**: The watcher uses synchronous `git` subprocess calls inside the debounce flush. Since we're on a dedicated thread with no parallelism, there's no concurrent commit risk within the watcher. If a mutation handler commits first, `git commit` exits with "nothing to commit" and the watcher skips gracefully while still broadcasting the event. diff --git a/.storkit/work/6_archived/62_story_allow_frontend_ui_to_accept_permissions_requests.md b/.huskies/work/6_archived/62_story_allow_frontend_ui_to_accept_permissions_requests.md similarity index 100% rename from .storkit/work/6_archived/62_story_allow_frontend_ui_to_accept_permissions_requests.md rename to .huskies/work/6_archived/62_story_allow_frontend_ui_to_accept_permissions_requests.md diff --git a/.storkit/work/6_archived/63_story_auto_spawn_mergemaster_on_merge.md b/.huskies/work/6_archived/63_story_auto_spawn_mergemaster_on_merge.md similarity index 100% rename from .storkit/work/6_archived/63_story_auto_spawn_mergemaster_on_merge.md rename to .huskies/work/6_archived/63_story_auto_spawn_mergemaster_on_merge.md diff --git a/.storkit/work/6_archived/64_story_watcher_should_ignore_worktree_code_changes.md b/.huskies/work/6_archived/64_story_watcher_should_ignore_worktree_code_changes.md similarity index 100% rename from .storkit/work/6_archived/64_story_watcher_should_ignore_worktree_code_changes.md rename to .huskies/work/6_archived/64_story_watcher_should_ignore_worktree_code_changes.md diff --git a/.storkit/work/6_archived/65_story_standardised_script_test_entry_point_for_all_projects.md b/.huskies/work/6_archived/65_story_standardised_script_test_entry_point_for_all_projects.md similarity index 94% rename from .storkit/work/6_archived/65_story_standardised_script_test_entry_point_for_all_projects.md rename to .huskies/work/6_archived/65_story_standardised_script_test_entry_point_for_all_projects.md index 2a7f55fe..8f071b97 100644 --- a/.storkit/work/6_archived/65_story_standardised_script_test_entry_point_for_all_projects.md +++ b/.huskies/work/6_archived/65_story_standardised_script_test_entry_point_for_all_projects.md @@ -15,7 +15,7 @@ As a Story Kit user, I want every project initialised by Story Kit to have a scr - [ ] The Rust server can invoke script/test as the canonical way to run all tests for any project - [ ] Agents use script/test instead of guessing test commands — they only need to check output if exit code is non-zero, saving LLM tokens - [ ] script/test exits 0 on success, non-zero on failure — agents treat it as a single pass/fail gate without parsing output on success -- [ ] For this project (storkit-app), script/test runs cargo test, pnpm test, and pnpm test:e2e +- [ ] For this project (huskies-app), script/test runs cargo test, pnpm test, and pnpm test:e2e ## Out of Scope diff --git a/.storkit/work/6_archived/67_story_server_drives_pipeline_as_state_machine.md b/.huskies/work/6_archived/67_story_server_drives_pipeline_as_state_machine.md similarity index 100% rename from .storkit/work/6_archived/67_story_server_drives_pipeline_as_state_machine.md rename to .huskies/work/6_archived/67_story_server_drives_pipeline_as_state_machine.md diff --git a/.storkit/work/6_archived/68_story_frontend_pipeline_state_stale_after_server_restart.md b/.huskies/work/6_archived/68_story_frontend_pipeline_state_stale_after_server_restart.md similarity index 100% rename from .storkit/work/6_archived/68_story_frontend_pipeline_state_stale_after_server_restart.md rename to .huskies/work/6_archived/68_story_frontend_pipeline_state_stale_after_server_restart.md diff --git a/.storkit/work/6_archived/69_story_test_coverage_qa_gate.md b/.huskies/work/6_archived/69_story_test_coverage_qa_gate.md similarity index 100% rename from .storkit/work/6_archived/69_story_test_coverage_qa_gate.md rename to .huskies/work/6_archived/69_story_test_coverage_qa_gate.md diff --git a/.storkit/work/6_archived/70_story_server_owned_agent_completion_remove_report_completion_dependency.md b/.huskies/work/6_archived/70_story_server_owned_agent_completion_remove_report_completion_dependency.md similarity index 95% rename from .storkit/work/6_archived/70_story_server_owned_agent_completion_remove_report_completion_dependency.md rename to .huskies/work/6_archived/70_story_server_owned_agent_completion_remove_report_completion_dependency.md index 45234bad..b5f359d6 100644 --- a/.storkit/work/6_archived/70_story_server_owned_agent_completion_remove_report_completion_dependency.md +++ b/.huskies/work/6_archived/70_story_server_owned_agent_completion_remove_report_completion_dependency.md @@ -6,7 +6,7 @@ name: "Server-owned agent completion: remove report_completion dependency" ## User Story -As a developer using storkit, I want the server to automatically run acceptance +As a developer using huskies, I want the server to automatically run acceptance gates and advance the pipeline when an agent process exits, so that the pipeline does not stall when an agent forgets or fails to call `report_completion`. diff --git a/.storkit/work/6_archived/71_bug_server_health_endpoint_missing.md b/.huskies/work/6_archived/71_bug_server_health_endpoint_missing.md similarity index 95% rename from .storkit/work/6_archived/71_bug_server_health_endpoint_missing.md rename to .huskies/work/6_archived/71_bug_server_health_endpoint_missing.md index f12bdb24..ed36ddbf 100644 --- a/.storkit/work/6_archived/71_bug_server_health_endpoint_missing.md +++ b/.huskies/work/6_archived/71_bug_server_health_endpoint_missing.md @@ -10,7 +10,7 @@ GET /api/health returns 404 not found. The server should have a health check end ## How to Reproduce -1. Start the storkit server +1. Start the huskies server 2. curl http://localhost:3001/api/health 3. Observe 404 not found response diff --git a/.storkit/work/6_archived/72_bug_story_creation_does_not_quote_yaml_special_characters_in_name.md b/.huskies/work/6_archived/72_bug_story_creation_does_not_quote_yaml_special_characters_in_name.md similarity index 100% rename from .storkit/work/6_archived/72_bug_story_creation_does_not_quote_yaml_special_characters_in_name.md rename to .huskies/work/6_archived/72_bug_story_creation_does_not_quote_yaml_special_characters_in_name.md diff --git a/.storkit/work/6_archived/73_story_fade_out_completed_agents.md b/.huskies/work/6_archived/73_story_fade_out_completed_agents.md similarity index 100% rename from .storkit/work/6_archived/73_story_fade_out_completed_agents.md rename to .huskies/work/6_archived/73_story_fade_out_completed_agents.md diff --git a/.storkit/work/6_archived/74_story_agent_lozenges_float_across_ui_during_assignment.md b/.huskies/work/6_archived/74_story_agent_lozenges_float_across_ui_during_assignment.md similarity index 100% rename from .storkit/work/6_archived/74_story_agent_lozenges_float_across_ui_during_assignment.md rename to .huskies/work/6_archived/74_story_agent_lozenges_float_across_ui_during_assignment.md diff --git a/.storkit/work/6_archived/77_bug_create_bug_file_writes_no_yaml_front_matter.md b/.huskies/work/6_archived/77_bug_create_bug_file_writes_no_yaml_front_matter.md similarity index 100% rename from .storkit/work/6_archived/77_bug_create_bug_file_writes_no_yaml_front_matter.md rename to .huskies/work/6_archived/77_bug_create_bug_file_writes_no_yaml_front_matter.md diff --git a/.storkit/work/6_archived/78_story_create_spike_mcp_tool.md b/.huskies/work/6_archived/78_story_create_spike_mcp_tool.md similarity index 100% rename from .storkit/work/6_archived/78_story_create_spike_mcp_tool.md rename to .huskies/work/6_archived/78_story_create_spike_mcp_tool.md diff --git a/.storkit/work/6_archived/79_story_agents_panel_skips_archived_work_on_startup.md b/.huskies/work/6_archived/79_story_agents_panel_skips_archived_work_on_startup.md similarity index 100% rename from .storkit/work/6_archived/79_story_agents_panel_skips_archived_work_on_startup.md rename to .huskies/work/6_archived/79_story_agents_panel_skips_archived_work_on_startup.md diff --git a/.storkit/work/6_archived/80_story_remove_model_apikey_and_rate_limit_notifications_from_chat_ui.md b/.huskies/work/6_archived/80_story_remove_model_apikey_and_rate_limit_notifications_from_chat_ui.md similarity index 100% rename from .storkit/work/6_archived/80_story_remove_model_apikey_and_rate_limit_notifications_from_chat_ui.md rename to .huskies/work/6_archived/80_story_remove_model_apikey_and_rate_limit_notifications_from_chat_ui.md diff --git a/.storkit/work/6_archived/81_story_agent_roster_badges_show_availability_state.md b/.huskies/work/6_archived/81_story_agent_roster_badges_show_availability_state.md similarity index 100% rename from .storkit/work/6_archived/81_story_agent_roster_badges_show_availability_state.md rename to .huskies/work/6_archived/81_story_agent_roster_badges_show_availability_state.md diff --git a/.storkit/work/6_archived/82_story_shift_enter_inserts_newline_instead_of_sending_in_chat_input.md b/.huskies/work/6_archived/82_story_shift_enter_inserts_newline_instead_of_sending_in_chat_input.md similarity index 100% rename from .storkit/work/6_archived/82_story_shift_enter_inserts_newline_instead_of_sending_in_chat_input.md rename to .huskies/work/6_archived/82_story_shift_enter_inserts_newline_instead_of_sending_in_chat_input.md diff --git a/.storkit/work/6_archived/83_story_remove_active_work_list_from_agents_panel.md b/.huskies/work/6_archived/83_story_remove_active_work_list_from_agents_panel.md similarity index 100% rename from .storkit/work/6_archived/83_story_remove_active_work_list_from_agents_panel.md rename to .huskies/work/6_archived/83_story_remove_active_work_list_from_agents_panel.md diff --git a/.storkit/work/6_archived/84_story_sparse_checkout_excludes_pipeline_files_from_agent_worktrees.md b/.huskies/work/6_archived/84_story_sparse_checkout_excludes_pipeline_files_from_agent_worktrees.md similarity index 100% rename from .storkit/work/6_archived/84_story_sparse_checkout_excludes_pipeline_files_from_agent_worktrees.md rename to .huskies/work/6_archived/84_story_sparse_checkout_excludes_pipeline_files_from_agent_worktrees.md diff --git a/.storkit/work/6_archived/85_story_agent_lozenges_move_between_roster_and_work_items_instead_of_duplicating.md b/.huskies/work/6_archived/85_story_agent_lozenges_move_between_roster_and_work_items_instead_of_duplicating.md similarity index 100% rename from .storkit/work/6_archived/85_story_agent_lozenges_move_between_roster_and_work_items_instead_of_duplicating.md rename to .huskies/work/6_archived/85_story_agent_lozenges_move_between_roster_and_work_items_instead_of_duplicating.md diff --git a/.storkit/work/6_archived/86_story_show_live_activity_status_instead_of_static_thinking_indicator_in_chat.md b/.huskies/work/6_archived/86_story_show_live_activity_status_instead_of_static_thinking_indicator_in_chat.md similarity index 100% rename from .storkit/work/6_archived/86_story_show_live_activity_status_instead_of_static_thinking_indicator_in_chat.md rename to .huskies/work/6_archived/86_story_show_live_activity_status_instead_of_static_thinking_indicator_in_chat.md diff --git a/.storkit/work/6_archived/87_story_update_agent_lozenge_colour_scheme_across_panels.md b/.huskies/work/6_archived/87_story_update_agent_lozenge_colour_scheme_across_panels.md similarity index 100% rename from .storkit/work/6_archived/87_story_update_agent_lozenge_colour_scheme_across_panels.md rename to .huskies/work/6_archived/87_story_update_agent_lozenge_colour_scheme_across_panels.md diff --git a/.storkit/work/6_archived/88_story_auto_assign_agents_to_available_work_on_server_startup.md b/.huskies/work/6_archived/88_story_auto_assign_agents_to_available_work_on_server_startup.md similarity index 100% rename from .storkit/work/6_archived/88_story_auto_assign_agents_to_available_work_on_server_startup.md rename to .huskies/work/6_archived/88_story_auto_assign_agents_to_available_work_on_server_startup.md diff --git a/.storkit/work/6_archived/89_story_persistent_per_session_agent_logs.md b/.huskies/work/6_archived/89_story_persistent_per_session_agent_logs.md similarity index 100% rename from .storkit/work/6_archived/89_story_persistent_per_session_agent_logs.md rename to .huskies/work/6_archived/89_story_persistent_per_session_agent_logs.md diff --git a/.storkit/work/6_archived/90_story_fetch_real_context_window_size_from_anthropic_models_api.md b/.huskies/work/6_archived/90_story_fetch_real_context_window_size_from_anthropic_models_api.md similarity index 100% rename from .storkit/work/6_archived/90_story_fetch_real_context_window_size_from_anthropic_models_api.md rename to .huskies/work/6_archived/90_story_fetch_real_context_window_size_from_anthropic_models_api.md diff --git a/.storkit/work/6_archived/91_bug_permissions_dialog_never_triggers_in_web_ui.md b/.huskies/work/6_archived/91_bug_permissions_dialog_never_triggers_in_web_ui.md similarity index 98% rename from .storkit/work/6_archived/91_bug_permissions_dialog_never_triggers_in_web_ui.md rename to .huskies/work/6_archived/91_bug_permissions_dialog_never_triggers_in_web_ui.md index aa9865cc..45134b0f 100644 --- a/.storkit/work/6_archived/91_bug_permissions_dialog_never_triggers_in_web_ui.md +++ b/.huskies/work/6_archived/91_bug_permissions_dialog_never_triggers_in_web_ui.md @@ -20,7 +20,7 @@ The correct mechanism for non-interactive permission handling is the `--permissi ## How to Reproduce -1. Start the storkit server +1. Start the huskies server 2. Open the web UI and select claude-code-pty as the model 3. Send a message that triggers a tool requiring permission (e.g. "search the web for something") 4. Observe that no permission dialog appears — the tool either auto-approves or the denial appears as text in the tool drawer @@ -54,7 +54,7 @@ A full-screen permission dialog appears showing the tool name and input, with Ap - On receiving `WsRequest::PermissionResponse` from the client, send the decision back through the oneshot sender ### 5. Update Claude Code spawning (`server/src/llm/providers/claude_code.rs`) -- Add `--permission-prompt-tool mcp__storkit__prompt_permission` to the CLI args +- Add `--permission-prompt-tool mcp__huskies__prompt_permission` to the CLI args - Remove `PermissionReqMsg` struct and `permission_tx` parameter (no longer needed — permissions flow through MCP, not PTY) - Clean up the triple-duplicate `permission_request` match arms (dead code from story 80 merge) diff --git a/.storkit/work/6_archived/92_spike_stop_auto_committing_intermediate_pipeline_moves.md b/.huskies/work/6_archived/92_spike_stop_auto_committing_intermediate_pipeline_moves.md similarity index 96% rename from .storkit/work/6_archived/92_spike_stop_auto_committing_intermediate_pipeline_moves.md rename to .huskies/work/6_archived/92_spike_stop_auto_committing_intermediate_pipeline_moves.md index a7d2cd5e..72372aa0 100644 --- a/.storkit/work/6_archived/92_spike_stop_auto_committing_intermediate_pipeline_moves.md +++ b/.huskies/work/6_archived/92_spike_stop_auto_committing_intermediate_pipeline_moves.md @@ -13,11 +13,11 @@ Determine how to stop the filesystem watcher from auto-committing every pipeline ## Context The watcher in `server/src/io/watcher.rs` currently auto-commits every file change in `.story_kit/work/`. A single story run generates 5+ commits just from pipeline moves: -- `storkit: create 42_story_foo` -- `storkit: start 42_story_foo` -- `storkit: queue 42_story_foo for QA` -- `storkit: queue 42_story_foo for merge` -- `storkit: accept 42_story_foo` +- `huskies: create 42_story_foo` +- `huskies: start 42_story_foo` +- `huskies: queue 42_story_foo for QA` +- `huskies: queue 42_story_foo for merge` +- `huskies: accept 42_story_foo` Since story runs complete relatively quickly, the intermediate state (current/qa/merge) is transient and doesn't need to be committed. Only creation and archival are meaningful checkpoints. @@ -105,8 +105,8 @@ Prototype implemented: added `COMMIT_WORTHY_STAGES` constant and `should_commit_ - All 872 tests pass, clippy clean A full story run will now produce only 2 pipeline commits instead of 5+: -- `storkit: create 42_story_foo` (creation in `1_upcoming`) -- `storkit: accept 42_story_foo` (archival in `6_archived`) +- `huskies: create 42_story_foo` (creation in `1_upcoming`) +- `huskies: accept 42_story_foo` (archival in `6_archived`) The intermediate moves (`start`, `queue for QA`, `queue for merge`, `done`) are still broadcast to WebSocket clients for real-time frontend updates, but no longer clutter git history. diff --git a/.storkit/work/6_archived/93_bug_agent_session_id_is_null_while_running.md b/.huskies/work/6_archived/93_bug_agent_session_id_is_null_while_running.md similarity index 100% rename from .storkit/work/6_archived/93_bug_agent_session_id_is_null_while_running.md rename to .huskies/work/6_archived/93_bug_agent_session_id_is_null_while_running.md diff --git a/.storkit/work/6_archived/93_story_expose_server_logs_to_agents_via_mcp.md b/.huskies/work/6_archived/93_story_expose_server_logs_to_agents_via_mcp.md similarity index 100% rename from .storkit/work/6_archived/93_story_expose_server_logs_to_agents_via_mcp.md rename to .huskies/work/6_archived/93_story_expose_server_logs_to_agents_via_mcp.md diff --git a/.storkit/work/6_archived/94_bug_stale_agent_state_persists_after_server_restart.md b/.huskies/work/6_archived/94_bug_stale_agent_state_persists_after_server_restart.md similarity index 100% rename from .storkit/work/6_archived/94_bug_stale_agent_state_persists_after_server_restart.md rename to .huskies/work/6_archived/94_bug_stale_agent_state_persists_after_server_restart.md diff --git a/.storkit/work/6_archived/95_bug_pipeline_auto_restart_has_no_retry_limit_causing_infinite_loop.md b/.huskies/work/6_archived/95_bug_pipeline_auto_restart_has_no_retry_limit_causing_infinite_loop.md similarity index 100% rename from .storkit/work/6_archived/95_bug_pipeline_auto_restart_has_no_retry_limit_causing_infinite_loop.md rename to .huskies/work/6_archived/95_bug_pipeline_auto_restart_has_no_retry_limit_causing_infinite_loop.md diff --git a/.storkit/work/6_archived/96_story_reset_agent_lozenge_to_idle_state_when_returning_to_roster.md b/.huskies/work/6_archived/96_story_reset_agent_lozenge_to_idle_state_when_returning_to_roster.md similarity index 100% rename from .storkit/work/6_archived/96_story_reset_agent_lozenge_to_idle_state_when_returning_to_roster.md rename to .huskies/work/6_archived/96_story_reset_agent_lozenge_to_idle_state_when_returning_to_roster.md diff --git a/.storkit/work/6_archived/97_bug_agent_pool_allows_multiple_instances_of_the_same_agent_to_run_concurrently.md b/.huskies/work/6_archived/97_bug_agent_pool_allows_multiple_instances_of_the_same_agent_to_run_concurrently.md similarity index 100% rename from .storkit/work/6_archived/97_bug_agent_pool_allows_multiple_instances_of_the_same_agent_to_run_concurrently.md rename to .huskies/work/6_archived/97_bug_agent_pool_allows_multiple_instances_of_the_same_agent_to_run_concurrently.md diff --git a/.storkit/work/6_archived/98_story_expand_work_item_to_full_screen_detail_view.md b/.huskies/work/6_archived/98_story_expand_work_item_to_full_screen_detail_view.md similarity index 100% rename from .storkit/work/6_archived/98_story_expand_work_item_to_full_screen_detail_view.md rename to .huskies/work/6_archived/98_story_expand_work_item_to_full_screen_detail_view.md diff --git a/.storkit/work/6_archived/99_story_test_coverage_http_health_rs_to_100.md b/.huskies/work/6_archived/99_story_test_coverage_http_health_rs_to_100.md similarity index 100% rename from .storkit/work/6_archived/99_story_test_coverage_http_health_rs_to_100.md rename to .huskies/work/6_archived/99_story_test_coverage_http_health_rs_to_100.md diff --git a/.ignore b/.ignore index 518d0623..cbf4343c 100644 --- a/.ignore +++ b/.ignore @@ -3,6 +3,6 @@ frontend/ node_modules/ .claude/ .git/ -.storkit/ +.huskies/ store.json -.storkit_port +.huskies_port diff --git a/.storkit/work/6_archived/294_story_rename_app_title_from_story_kit_to_storkit.md b/.storkit/work/6_archived/294_story_rename_app_title_from_story_kit_to_storkit.md deleted file mode 100644 index 5b162310..00000000 --- a/.storkit/work/6_archived/294_story_rename_app_title_from_story_kit_to_storkit.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: "Rename app title from Story Kit to Storkit" -review_hold: true ---- - -# Story 294: Rename app title from Story Kit to Storkit - -## User Story - -As a user, I want the application title to say "Storkit" instead of "Story Kit", so that the branding reflects the new name. - -## Acceptance Criteria - -- [ ] The top title in the web UI header displays "Storkit" instead of "Story Kit" -- [ ] Any other visible references to "Story Kit" in the UI are updated to "Storkit" - -## Out of Scope - -- TBD diff --git a/.storkit/work/6_archived/315_story_rename_binary_and_all_references_from_story_kit_to_storkit.md b/.storkit/work/6_archived/315_story_rename_binary_and_all_references_from_story_kit_to_storkit.md deleted file mode 100644 index 77edc292..00000000 --- a/.storkit/work/6_archived/315_story_rename_binary_and_all_references_from_story_kit_to_storkit.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -name: "Rename binary and all references from storkit to storkit" -agent: coder-opus ---- - -# Story 315: Rename binary and all references from storkit to storkit - -## User Story - -As a project owner, I want the binary, crate name, package name, and all code/config references renamed from storkit/story_kit to storkit, so that the branding is consistent throughout the project. - -## Acceptance Criteria - -- [ ] Binary name changed from storkit to storkit in Cargo.toml -- [ ] Crate/package name changed from storkit/story_kit to storkit throughout Cargo.toml files -- [ ] All code references to story_kit (module names, paths, env vars like CARGO_MANIFEST_DIR) updated -- [ ] Config directory .story_kit renamed to .storkit -- [ ] All server code references to .story_kit paths updated -- [ ] Git commit messages prefix changed from 'storkit:' to 'storkit:' -- [ ] Frontend references updated (if any) -- [ ] script/* files updated to reference the new binary name -- [ ] Release script updated for new binary name -- [ ] MCP server name updated from storkit to storkit -- [ ] CLAUDE.md and README references updated - -## Out of Scope - -- TBD diff --git a/.storkit/work/6_archived/371_bug_no_arg_storkit_in_empty_directory_skips_scaffold.md b/.storkit/work/6_archived/371_bug_no_arg_storkit_in_empty_directory_skips_scaffold.md deleted file mode 100644 index 4c85493b..00000000 --- a/.storkit/work/6_archived/371_bug_no_arg_storkit_in_empty_directory_skips_scaffold.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -name: "No-arg storkit in empty directory skips scaffold" ---- - -# Bug 371: No-arg storkit in empty directory skips scaffold - -## Description - -When running `storkit` with no path argument from an empty directory (no `.storkit/`), the server starts but never calls `open_project` or the scaffold. The `find_story_kit_root` check fails to find `.storkit/`, so the fallback at main.rs:179-186 just sets `project_root = cwd` without scaffolding. This means no `.storkit/`, no `project.toml`, no `.mcp.json`, no `CLAUDE.md` — the project is non-functional. - -The explicit path branch (`storkit .`) works correctly because it calls `open_project` → `ensure_project_root_with_story_kit` → `scaffold_story_kit`. The no-arg branch should do the same. - -## How to Reproduce - -1. Create a new empty directory -2. cd into it -3. Run `storkit` (no path argument) -4. Observe that no scaffold is created — `.storkit/`, `CLAUDE.md`, `.mcp.json`, etc. are all missing - -## Actual Result - -Server starts with project_root set to cwd but no scaffold runs. The project is non-functional — no agent config, no MCP endpoint, no work pipeline directories. - -## Expected Result - -Running `storkit` with no arguments from a directory without `.storkit/` should scaffold the project the same as `storkit .` does — calling `open_project` and triggering `ensure_project_root_with_story_kit`. - -## Acceptance Criteria - -- [ ] Running `storkit` with no args from a dir without `.storkit/` calls `open_project` and triggers the full scaffold -- [ ] The no-arg fallback path in main.rs calls `open_project(cwd)` instead of just setting project_root directly -- [ ] After `storkit` completes startup, `.storkit/project.toml`, `.mcp.json`, `CLAUDE.md`, and `script/test` all exist diff --git a/CLAUDE.md b/CLAUDE.md index e6ccd08d..9ce75898 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,3 +1,3 @@ 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. -Read .storkit/README.md to see our dev process. +Read .huskies/README.md to see our dev process. diff --git a/Cargo.lock b/Cargo.lock index d5e9791f..1af800d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1505,6 +1505,48 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "huskies" +version = "0.8.8" +dependencies = [ + "async-stream", + "async-trait", + "bytes", + "chrono", + "chrono-tz", + "eventsource-stream", + "filetime", + "futures", + "homedir", + "ignore", + "libc", + "libsqlite3-sys", + "matrix-sdk", + "mime_guess", + "mockito", + "notify", + "poem", + "poem-openapi", + "portable-pty", + "pulldown-cmark", + "regex", + "reqwest 0.13.2", + "rust-embed", + "serde", + "serde_json", + "serde_urlencoded", + "serde_yaml", + "sha2 0.11.0", + "strip-ansi-escapes", + "tempfile", + "tokio", + "tokio-tungstenite 0.29.0", + "toml 1.1.2+spec-1.1.0", + "uuid", + "wait-timeout", + "walkdir", +] + [[package]] name = "hybrid-array" version = "0.4.10" @@ -4103,48 +4145,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" -[[package]] -name = "storkit" -version = "0.8.8" -dependencies = [ - "async-stream", - "async-trait", - "bytes", - "chrono", - "chrono-tz", - "eventsource-stream", - "filetime", - "futures", - "homedir", - "ignore", - "libc", - "libsqlite3-sys", - "matrix-sdk", - "mime_guess", - "mockito", - "notify", - "poem", - "poem-openapi", - "portable-pty", - "pulldown-cmark", - "regex", - "reqwest 0.13.2", - "rust-embed", - "serde", - "serde_json", - "serde_urlencoded", - "serde_yaml", - "sha2 0.11.0", - "strip-ansi-escapes", - "tempfile", - "tokio", - "tokio-tungstenite 0.29.0", - "toml 1.1.2+spec-1.1.0", - "uuid", - "wait-timeout", - "walkdir", -] - [[package]] name = "string_cache" version = "0.8.9" diff --git a/README.md b/README.md index 47d04a1e..3a122034 100644 --- a/README.md +++ b/README.md @@ -1,37 +1,37 @@ -# Storkit +# Huskies A story-driven development server that manages work items, spawns coding agents, and runs them through a pipeline from backlog to done. Ships as a single Rust binary with an embedded React frontend. ## Getting started with Claude Code -1. Download the storkit binary (or build from source — see below). +1. Download the huskies binary (or build from source — see below). 2. From your project directory, scaffold and start the server: ```bash -storkit init --port 3000 +huskies init --port 3000 ``` -This creates a `.storkit/` directory with the pipeline structure, `project.toml`, and `.mcp.json`. The `.mcp.json` file lets Claude Code discover storkit's MCP tools automatically. +This creates a `.huskies/` directory with the pipeline structure, `project.toml`, and `.mcp.json`. The `.mcp.json` file lets Claude Code discover huskies' MCP tools automatically. 3. Open a Claude Code session in the same project directory. Claude will pick up the MCP tools from `.mcp.json`. -4. Tell Claude: "help me set up this project with storkit." Claude will walk you through the setup wizard — generating project context, tech stack docs, and test/release scripts. Review each step and confirm or ask to retry. +4. Tell Claude: "help me set up this project with huskies." Claude will walk you through the setup wizard — generating project context, tech stack docs, and test/release scripts. Review each step and confirm or ask to retry. Once setup is complete, Claude can create stories, start agents, check status, and manage the full pipeline via MCP tools — no commands to memorize. ## Web UI -Storkit also ships an embedded React frontend. Once the server is running, open `http://localhost:3000` to see the pipeline board, agent status, and chat interface. +Huskies also ships an embedded React frontend. Once the server is running, open `http://localhost:3000` to see the pipeline board, agent status, and chat interface. ## Chat transports -Storkit can be controlled via bot commands in **Matrix**, **WhatsApp**, and **Slack**. Configure a transport in `.storkit/bot.toml` — see the example files: +Huskies can be controlled via bot commands in **Matrix**, **WhatsApp**, and **Slack**. Configure a transport in `.huskies/bot.toml` — see the example files: -- `.storkit/bot.toml.matrix.example` -- `.storkit/bot.toml.whatsapp-meta.example` -- `.storkit/bot.toml.whatsapp-twilio.example` -- `.storkit/bot.toml.slack.example` +- `.huskies/bot.toml.matrix.example` +- `.huskies/bot.toml.whatsapp-meta.example` +- `.huskies/bot.toml.whatsapp-twilio.example` +- `.huskies/bot.toml.slack.example` ## Prerequisites @@ -46,7 +46,7 @@ Storkit can be controlled via bot commands in **Matrix**, **WhatsApp**, and **Sl cargo build --release ``` -The release binary embeds the frontend via `rust-embed`. Output: `target/release/storkit`. +The release binary embeds the frontend via `rust-embed`. Output: `target/release/huskies`. For a static Linux binary (musl, zero dynamic deps): @@ -73,7 +73,7 @@ cargo run -- --port 3000 cd frontend && npm install && npm run dev ``` -Configuration lives in `.storkit/project.toml`. See `.storkit/bot.toml.*.example` for transport setup. +Configuration lives in `.huskies/project.toml`. See `.huskies/bot.toml.*.example` for transport setup. ## Releasing diff --git a/docker/.dockerignore b/docker/.dockerignore index ec606cf4..201beba3 100644 --- a/docker/.dockerignore +++ b/docker/.dockerignore @@ -2,9 +2,9 @@ **/target/ **/node_modules/ frontend/dist/ -.storkit/worktrees/ -.storkit/logs/ -.storkit/work/6_archived/ +.huskies/worktrees/ +.huskies/logs/ +.huskies/work/6_archived/ .git/ *.swp *.swo diff --git a/docker/Dockerfile b/docker/Dockerfile index daf5ed05..2adc1102 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,8 +1,8 @@ -# Story Kit – single-container runtime +# Huskies – single-container runtime # All components (server, agents, web UI) run inside this container. # The target project repo is bind-mounted at /workspace. # -# Build: docker build -t storkit -f docker/Dockerfile . +# Build: docker build -t huskies -f docker/Dockerfile . # Run: docker compose -f docker/docker-compose.yml up # # Tested with: OrbStack (recommended on macOS), Docker Desktop (slower bind mounts) @@ -37,11 +37,11 @@ RUN curl -LsSf https://get.nexte.st/latest/linux | tar zxf - -C /usr/local/bin RUN npm install -g @anthropic-ai/claude-code # ── Working directory ──────────────────────────────────────────────── -# /app holds the storkit source (copied in at build time for the binary). +# /app holds the huskies source (copied in at build time for the binary). # /workspace is where the target project repo gets bind-mounted at runtime. WORKDIR /app -# ── Build the storkit server binary ───────────────────────────────── +# ── Build the huskies server binary ───────────────────────────────── # Copy the full project tree so `cargo build` and `npm run build` (via # build.rs) can produce the release binary with embedded frontend assets. COPY . . @@ -51,7 +51,7 @@ RUN cd frontend && npm ci # Build the release binary (build.rs runs npm run build for the frontend) RUN cargo build --release \ - && cp target/release/storkit /usr/local/bin/storkit + && cp target/release/huskies /usr/local/bin/huskies # ── Runtime stage (smaller image) ─────────────────────────────────── FROM debian:bookworm-slim AS runtime @@ -91,8 +91,8 @@ ENV CARGO_HOME="/usr/local/cargo" # cargo-nextest COPY --from=base /usr/local/bin/cargo-nextest /usr/local/bin/cargo-nextest -# The storkit binary -COPY --from=base /usr/local/bin/storkit /usr/local/bin/storkit +# The huskies binary +COPY --from=base /usr/local/bin/huskies /usr/local/bin/huskies # Copy the full source tree so rebuild_and_restart can do `cargo build` # from the workspace root (CARGO_MANIFEST_DIR is baked into the binary). @@ -102,21 +102,21 @@ COPY --from=base /app /app # ── Non-root user ──────────────────────────────────────────────────── # Claude Code refuses --dangerously-skip-permissions (bypassPermissions) # when running as root. Create a dedicated user so agents can launch. -RUN groupadd -r storkit \ - && useradd -r -g storkit -m -d /home/storkit storkit \ - && mkdir -p /home/storkit/.claude \ - && chown -R storkit:storkit /home/storkit \ - && chown -R storkit:storkit /usr/local/cargo /usr/local/rustup \ - && chown -R storkit:storkit /app \ +RUN groupadd -r huskies \ + && useradd -r -g huskies -m -d /home/huskies huskies \ + && mkdir -p /home/huskies/.claude \ + && chown -R huskies:huskies /home/huskies \ + && chown -R huskies:huskies /usr/local/cargo /usr/local/rustup \ + && chown -R huskies:huskies /app \ && mkdir -p /workspace/target /app/target \ - && chown storkit:storkit /workspace/target /app/target + && chown huskies:huskies /workspace/target /app/target # ── Entrypoint ─────────────────────────────────────────────────────── # Validates required env vars (GIT_USER_NAME, GIT_USER_EMAIL) and # configures git identity before starting the server. COPY docker/entrypoint.sh /usr/local/bin/entrypoint.sh -USER storkit +USER huskies WORKDIR /workspace # ── Ports ──────────────────────────────────────────────────────────── @@ -125,8 +125,8 @@ EXPOSE 3001 # ── Volumes (defined in docker-compose.yml) ────────────────────────── # /workspace – bind mount: target project repo -# /home/storkit/.claude – named volume: Claude Code sessions/state +# /home/huskies/.claude – named volume: Claude Code sessions/state # /usr/local/cargo/registry – named volume: cargo dependency cache ENTRYPOINT ["entrypoint.sh"] -CMD ["storkit", "/workspace"] +CMD ["huskies", "/workspace"] diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 3a5abc4b..f3d068a0 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -1,4 +1,4 @@ -# Story Kit – single-container deployment +# Huskies – single-container deployment # # Usage: # # Set your API key and project path, then: @@ -10,11 +10,11 @@ # Docker Desktop's default (see spike findings). services: - storkit: + huskies: build: context: .. dockerfile: docker/Dockerfile - container_name: storkit + container_name: huskies ports: # Bind to localhost only — not exposed on all interfaces. - "127.0.0.1:3001:3001" @@ -26,9 +26,9 @@ services: - GIT_USER_NAME=${GIT_USER_NAME:?Set GIT_USER_NAME} - GIT_USER_EMAIL=${GIT_USER_EMAIL:?Set GIT_USER_EMAIL} # Optional: override the server port (default 3001) - - STORKIT_PORT=3001 + - HUSKIES_PORT=3001 # Bind to all interfaces so Docker port forwarding works. - - STORKIT_HOST=0.0.0.0 + - HUSKIES_HOST=0.0.0.0 # Optional: Matrix bot credentials (if using Matrix integration) - MATRIX_HOMESERVER=${MATRIX_HOMESERVER:-} - MATRIX_USER=${MATRIX_USER:-} @@ -51,9 +51,9 @@ services: # Claude Code state – persists session history, projects config, # and conversation transcripts so --resume works across restarts. - - claude-state:/home/storkit/.claude + - claude-state:/home/huskies/.claude - # Storkit source tree for rebuild_and_restart. + # Huskies source tree for rebuild_and_restart. # The binary has CARGO_MANIFEST_DIR baked in at compile time # pointing to /app/server, so the source must be at /app. # This is COPY'd in the Dockerfile; mounting over it allows @@ -67,7 +67,7 @@ services: # on incremental builds — leaving it on the bind mount makes builds # catastrophically slow (~12s just to traverse the tree). - workspace-target:/workspace/target - - storkit-target:/app/target + - huskies-target:/app/target # ── Security hardening ────────────────────────────────────────── # Read-only root filesystem. Only explicitly mounted volumes and @@ -75,7 +75,7 @@ services: read_only: true tmpfs: - /tmp:size=512M,exec - - /home/storkit:size=512M,uid=999,gid=999,exec + - /home/huskies:size=512M,uid=999,gid=999,exec # Drop all Linux capabilities, then add back only what's needed. # SETUID/SETGID needed by Claude Code's PTY allocation (openpty). @@ -121,4 +121,4 @@ volumes: cargo-git: claude-state: workspace-target: - storkit-target: + huskies-target: diff --git a/frontend/index.html b/frontend/index.html index a1d2e54e..db1e9d62 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -4,7 +4,7 @@ - Storkit + Huskies diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index 3f690345..3a773604 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -212,7 +212,7 @@ export interface OAuthStatus { has_refresh_token: boolean; } -declare const __STORKIT_PORT__: string; +declare const __HUSKIES_PORT__: string; const DEFAULT_API_BASE = "/api"; const DEFAULT_WS_PATH = "/ws"; @@ -513,7 +513,7 @@ export class ChatWebSocket { const protocol = window.location.protocol === "https:" ? "wss" : "ws"; const wsHost = resolveWsHost( import.meta.env.DEV, - typeof __STORKIT_PORT__ !== "undefined" ? __STORKIT_PORT__ : undefined, + typeof __HUSKIES_PORT__ !== "undefined" ? __HUSKIES_PORT__ : undefined, window.location.host, ); return `${protocol}://${wsHost}${this.wsPath}`; diff --git a/frontend/src/components/Chat.tsx b/frontend/src/components/Chat.tsx index 3ac5e812..14cd9fff 100644 --- a/frontend/src/components/Chat.tsx +++ b/frontend/src/components/Chat.tsx @@ -1035,7 +1035,7 @@ export function Chat({ fontSize: "1.1rem", }} > - Welcome to Storkit + Welcome to Huskies

{ expect(screen.getByText("Built: 2026-01-01 00:00")).toBeInTheDocument(); }); - it("displays Storkit branding in the header", () => { + it("displays Huskies branding in the header", () => { render(); - expect(screen.getByText("Storkit")).toBeInTheDocument(); + expect(screen.getByText("Huskies")).toBeInTheDocument(); }); it("labels the claude-pty optgroup as 'Claude Code'", () => { diff --git a/frontend/src/components/ChatHeader.tsx b/frontend/src/components/ChatHeader.tsx index e8b925b0..3e374146 100644 --- a/frontend/src/components/ChatHeader.tsx +++ b/frontend/src/components/ChatHeader.tsx @@ -295,7 +295,7 @@ export function ChatHeader({ letterSpacing: "0.02em", }} > - Storkit + Huskies

= { context: - "Read the codebase and generate .storkit/specs/00_CONTEXT.md with a project context spec. Include High-Level Goal, Core Features, Domain Definition, and Glossary sections. Then call the wizard API to store the content: PUT /api/wizard/step/context/content", + "Read the codebase and generate .huskies/specs/00_CONTEXT.md with a project context spec. Include High-Level Goal, Core Features, Domain Definition, and Glossary sections. Then call the wizard API to store the content: PUT /api/wizard/step/context/content", stack: - "Read the tech stack and generate .storkit/specs/tech/STACK.md with a tech stack spec. Include Core Stack, Coding Standards, Quality Gates, and Libraries sections. Then call the wizard API to store the content: PUT /api/wizard/step/stack/content", + "Read the tech stack and generate .huskies/specs/tech/STACK.md with a tech stack spec. Include Core Stack, Coding Standards, Quality Gates, and Libraries sections. Then call the wizard API to store the content: PUT /api/wizard/step/stack/content", test_script: "Read the project structure and create script/test — a bash script that runs the project's actual test suite. Then call the wizard API: PUT /api/wizard/step/test_script/content", release_script: diff --git a/frontend/src/components/selection/SelectionScreen.test.tsx b/frontend/src/components/selection/SelectionScreen.test.tsx index 2a0aa80d..14179056 100644 --- a/frontend/src/components/selection/SelectionScreen.test.tsx +++ b/frontend/src/components/selection/SelectionScreen.test.tsx @@ -33,7 +33,7 @@ function makeProps( describe("SelectionScreen", () => { it("renders the title and description", () => { render(); - expect(screen.getByText("Storkit")).toBeInTheDocument(); + expect(screen.getByText("Huskies")).toBeInTheDocument(); expect( screen.getByText("Paste or complete a project path to start."), ).toBeInTheDocument(); diff --git a/frontend/src/components/selection/SelectionScreen.tsx b/frontend/src/components/selection/SelectionScreen.tsx index 5274f760..36d75b32 100644 --- a/frontend/src/components/selection/SelectionScreen.tsx +++ b/frontend/src/components/selection/SelectionScreen.tsx @@ -57,7 +57,7 @@ export function SelectionScreen({ className="selection-screen" style={{ padding: "2rem", maxWidth: "800px", margin: "0 auto" }} > -

Storkit

+

Huskies

Paste or complete a project path to start.

{oauthStatus !== null && ( diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index b54a7532..4c7aff24 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -3,11 +3,11 @@ import { defineConfig } from "vite"; // https://vite.dev/config/ export default defineConfig(() => { - const backendPort = Number(process.env.STORKIT_PORT || "3001"); + const backendPort = Number(process.env.HUSKIES_PORT || "3001"); return { plugins: [react()], define: { - __STORKIT_PORT__: JSON.stringify(String(backendPort)), + __HUSKIES_PORT__: JSON.stringify(String(backendPort)), __BUILD_TIME__: JSON.stringify(new Date().toISOString()), }, server: { diff --git a/script/migrate b/script/migrate new file mode 100755 index 00000000..f69598ce --- /dev/null +++ b/script/migrate @@ -0,0 +1,79 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Huskies migration script +# +# Migrates an existing storkit project to huskies by renaming the .storkit/ +# directory to .huskies/ and updating the .mcp.json server registration. +# +# Usage: +# script/migrate [PROJECT_PATH] +# +# If PROJECT_PATH is omitted, the current directory is used. + +PROJECT_PATH="${1:-$(pwd)}" + +if [ ! -d "$PROJECT_PATH" ]; then + echo "Error: '$PROJECT_PATH' is not a directory." + exit 1 +fi + +STORKIT_DIR="$PROJECT_PATH/.storkit" +HUSKIES_DIR="$PROJECT_PATH/.huskies" +MCP_JSON="$PROJECT_PATH/.mcp.json" + +echo "==> Migrating project at: $PROJECT_PATH" + +# ── Rename .storkit/ → .huskies/ ────────────────────────────────── +if [ -d "$STORKIT_DIR" ]; then + if [ -d "$HUSKIES_DIR" ]; then + echo " .huskies/ already exists — skipping directory rename." + else + mv "$STORKIT_DIR" "$HUSKIES_DIR" + echo " Renamed .storkit/ → .huskies/" + fi +else + if [ -d "$HUSKIES_DIR" ]; then + echo " .huskies/ already present (already migrated)." + else + echo " No .storkit/ or .huskies/ directory found — nothing to migrate." + exit 0 + fi +fi + +# ── Update .mcp.json ────────────────────────────────────────────── +if [ -f "$MCP_JSON" ]; then + if grep -q '"storkit"' "$MCP_JSON"; then + # Replace the MCP server key "storkit" with "huskies" + python3 -c " +import json, sys +with open(sys.argv[1]) as f: + cfg = json.load(f) +servers = cfg.get('mcpServers', {}) +if 'storkit' in servers and 'huskies' not in servers: + servers['huskies'] = servers.pop('storkit') +cfg['mcpServers'] = servers +with open(sys.argv[1], 'w') as f: + json.dump(cfg, f, indent=2) + f.write('\n') +" "$MCP_JSON" + echo " Updated .mcp.json: renamed mcpServers key 'storkit' → 'huskies'" + else + echo " .mcp.json already uses 'huskies' key — skipping." + fi +else + echo " No .mcp.json found — skipping." +fi + +# ── Update root-level .gitignore ────────────────────────────────── +GITIGNORE="$PROJECT_PATH/.gitignore" +if [ -f "$GITIGNORE" ]; then + if grep -q "\.storkit_port" "$GITIGNORE"; then + sed -i 's/\.storkit_port/\.huskies_port/g' "$GITIGNORE" + echo " Updated .gitignore: .storkit_port → .huskies_port" + fi +fi + +echo "" +echo "==> Migration complete." +echo " Restart huskies to pick up the new directory layout." diff --git a/script/release b/script/release index 5454a5a9..b909595c 100755 --- a/script/release +++ b/script/release @@ -3,8 +3,8 @@ set -euo pipefail # ── Configuration ────────────────────────────────────────────── GITEA_URL="https://code.crashlabs.io" -REPO="dave/storkit" -BINARY_NAME="storkit" +REPO="dave/huskies" +BINARY_NAME="huskies" # ── Load .env if present ─────────────────────────────────────── SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)" @@ -112,9 +112,9 @@ else fi # Extract completed stories/bugs/refactors from merge commits. -# Matches both the current "storkit:" prefix and the legacy "story-kit:" prefix. +# Matches the current "huskies:" prefix and legacy "storkit:" / "story-kit:" prefixes for backwards-compatible history parsing. # Deduplicate (a story may have been merged more than once after reverts). -MERGE_RE="^(storkit|story-kit): merge " +MERGE_RE="^(huskies|storkit|story-kit): merge " if [ -n "$LOG_RANGE" ]; then MERGED_RAW=$(git log "$LOG_RANGE" --pretty=format:"%s" --no-merges \ | grep -E "$MERGE_RE" | sed -E "s/$MERGE_RE//" | sort -u || true) @@ -143,14 +143,14 @@ done <<< "$MERGED_RAW" # Collect non-automation manual commits (direct fixes, version bumps, etc). if [ -n "$LOG_RANGE" ]; then MANUAL=$(git log "$LOG_RANGE" --pretty=format:"%s" --no-merges \ - | grep -Ev "^(storkit|story-kit): " \ - | grep -Ev "^Revert \"(storkit|story-kit): " \ + | grep -Ev "^(huskies|storkit|story-kit): " \ + | grep -Ev "^Revert \"(huskies|storkit|story-kit): " \ | grep -v "^Bump version" \ | sed 's/^/- /' || true) else MANUAL=$(git log --pretty=format:"%s" --no-merges \ - | grep -Ev "^(storkit|story-kit): " \ - | grep -Ev "^Revert \"(storkit|story-kit): " \ + | grep -Ev "^(huskies|storkit|story-kit): " \ + | grep -Ev "^Revert \"(huskies|storkit|story-kit): " \ | grep -v "^Bump version" \ | sed 's/^/- /' || true) fi diff --git a/script/test b/script/test index e5e6dd76..33e45a68 100755 --- a/script/test +++ b/script/test @@ -4,6 +4,16 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +echo "=== Building frontend ===" +if [ -d "$PROJECT_ROOT/frontend" ]; then + cd "$PROJECT_ROOT/frontend" + npm install + npm run build + cd "$PROJECT_ROOT" +else + echo "Skipping frontend build (no frontend directory)" +fi + echo "=== Running cargo clippy ===" cargo clippy --manifest-path "$PROJECT_ROOT/Cargo.toml" --all-targets --all-features diff --git a/server/Cargo.toml b/server/Cargo.toml index a4ba77d6..5d418279 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "storkit" +name = "huskies" version = "0.8.8" edition = "2024" build = "build.rs" diff --git a/server/src/agent_log.rs b/server/src/agent_log.rs index 842c54e8..2d35a3d9 100644 --- a/server/src/agent_log.rs +++ b/server/src/agent_log.rs @@ -17,7 +17,7 @@ pub struct LogEntry { /// Writes agent events to a persistent log file (JSONL format). /// /// Each agent session gets its own log file at: -/// `.storkit/logs/{story_id}/{agent_name}-{session_id}.log` +/// `.huskies/logs/{story_id}/{agent_name}-{session_id}.log` pub struct AgentLogWriter { file: File, } @@ -72,7 +72,7 @@ impl AgentLogWriter { /// Return the log directory for a story. fn log_dir(project_root: &Path, story_id: &str) -> PathBuf { project_root - .join(".storkit") + .join(".huskies") .join("logs") .join(story_id) } @@ -110,7 +110,7 @@ pub fn read_log(path: &Path) -> Result, String> { /// Find the most recent log file for a given story+agent combination. /// -/// Scans `.storkit/logs/{story_id}/` for files matching `{agent_name}-*.log` +/// Scans `.huskies/logs/{story_id}/` for files matching `{agent_name}-*.log` /// and returns the one with the most recent modification time. pub fn find_latest_log( project_root: &Path, @@ -162,7 +162,7 @@ mod tests { AgentLogWriter::new(root, "42_story_foo", "coder-1", "sess-abc123").unwrap(); let expected_path = root - .join(".storkit") + .join(".huskies") .join("logs") .join("42_story_foo") .join("coder-1-sess-abc123.log"); diff --git a/server/src/agents/lifecycle.rs b/server/src/agents/lifecycle.rs index 3a6896d3..c8e3bb60 100644 --- a/server/src/agents/lifecycle.rs +++ b/server/src/agents/lifecycle.rs @@ -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(".storkit").join("work").join("1_backlog") + project_root.join(".huskies").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(".storkit").join("work").join("5_done") + project_root.join(".huskies").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(".storkit").join("work"); + let sk = project_root.join(".huskies").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_done(project_root: &Path, story_id: &str) -> Result<(), String> { - let sk = project_root.join(".storkit").join("work"); + let sk = project_root.join(".huskies").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_done(project_root: &Path, story_id: &str) -> Result<(), Str /// 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(".storkit").join("work"); + let sk = project_root.join(".huskies").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(".storkit").join("work"); + let sk = project_root.join(".huskies").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(".storkit").join("work"); + let sk = project_root.join(".huskies").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(".storkit").join("work"); + let sk = project_root.join(".huskies").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(".storkit").join("work"); + let sk = project_root.join(".huskies").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(".storkit/work/1_backlog"); - let current = root.join(".storkit/work/2_current"); + let backlog = root.join(".huskies/work/1_backlog"); + let current = root.join(".huskies/work/2_current"); fs::create_dir_all(&backlog).unwrap(); fs::create_dir_all(¤t).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(".storkit/work/2_current"); + let current = root.join(".huskies/work/2_current"); fs::create_dir_all(¤t).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(".storkit/work/1_backlog"); - let current = root.join(".storkit/work/2_current"); + let backlog = root.join(".huskies/work/1_backlog"); + let current = root.join(".huskies/work/2_current"); fs::create_dir_all(&backlog).unwrap(); fs::create_dir_all(¤t).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(".storkit/work/2_current"); + let current = root.join(".huskies/work/2_current"); fs::create_dir_all(¤t).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(".storkit/work/5_done/2_bug_test.md").exists()); + assert!(root.join(".huskies/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(".storkit/work/1_backlog"); + let backlog = root.join(".huskies/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(".storkit/work/5_done/3_bug_test.md").exists()); + assert!(root.join(".huskies/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(".storkit/work/2_current"); + let current = root.join(".huskies/work/2_current"); fs::create_dir_all(¤t).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(".storkit/work/4_merge/20_story_foo.md").exists()); + assert!(root.join(".huskies/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(".storkit/work/3_qa"); + let qa_dir = root.join(".huskies/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(".storkit/work/4_merge/40_story_test.md").exists()); + assert!(root.join(".huskies/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(".storkit/work/4_merge"); + let merge_dir = root.join(".huskies/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(".storkit/work/2_current"); + let current = root.join(".huskies/work/2_current"); fs::create_dir_all(¤t).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(".storkit/work/3_qa/30_story_qa.md").exists()); + assert!(root.join(".huskies/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(".storkit/work/3_qa"); + let qa_dir = root.join(".huskies/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(".storkit/work/4_merge"); + let merge_dir = root.join(".huskies/work/4_merge"); fs::create_dir_all(&merge_dir).unwrap(); fs::write(merge_dir.join("22_story_test.md"), "test").unwrap(); move_story_to_done(root, "22_story_test").unwrap(); assert!(!merge_dir.join("22_story_test.md").exists()); - assert!(root.join(".storkit/work/5_done/22_story_test.md").exists()); + assert!(root.join(".huskies/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(".storkit/work/3_qa"); - let current_dir = root.join(".storkit/work/2_current"); + let qa_dir = root.join(".huskies/work/3_qa"); + let current_dir = root.join(".huskies/work/2_current"); fs::create_dir_all(&qa_dir).unwrap(); fs::create_dir_all(¤t_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(".storkit/work/2_current"); + let current_dir = root.join(".huskies/work/2_current"); fs::create_dir_all(¤t_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(".storkit/work/1_backlog"); - let current = root.join(".storkit/work/2_current"); + let backlog = root.join(".huskies/work/1_backlog"); + let current = root.join(".huskies/work/2_current"); fs::create_dir_all(&backlog).unwrap(); fs::create_dir_all(¤t).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(".storkit/work/2_current"); - let backlog = root.join(".storkit/work/1_backlog"); + let current = root.join(".huskies/work/2_current"); + let backlog = root.join(".huskies/work/1_backlog"); fs::create_dir_all(¤t).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(".storkit/work/2_current"); + let current = root.join(".huskies/work/2_current"); fs::create_dir_all(¤t).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(".storkit/work/3_qa"); - let backlog = root.join(".storkit/work/1_backlog"); + let qa_dir = root.join(".huskies/work/3_qa"); + let backlog = root.join(".huskies/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(); diff --git a/server/src/agents/merge.rs b/server/src/agents/merge.rs index 2aa06a4b..6124ea1d 100644 --- a/server/src/agents/merge.rs +++ b/server/src/agents/merge.rs @@ -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 `.storkit/merge_workspace` directory and +/// The merge pipeline uses a shared `.huskies/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". @@ -88,7 +88,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(".storkit").join("merge_workspace"); + let merge_wt_path = project_root.join(".huskies").join("merge_workspace"); // Ensure we start clean: remove any leftover merge workspace. cleanup_merge_workspace(project_root, &merge_wt_path, &merge_branch); @@ -189,7 +189,7 @@ pub(crate) fn run_squash_merge( // ── Commit in the temporary worktree ────────────────────────── all_output.push_str("=== git commit ===\n"); - let commit_msg = format!("storkit: merge {story_id}"); + let commit_msg = format!("huskies: merge {story_id}"); let commit = Command::new("git") .args(["commit", "-m", &commit_msg]) .current_dir(&merge_wt_path) @@ -238,7 +238,7 @@ pub(crate) fn run_squash_merge( } // ── Bug 226: Verify the commit contains real code changes ───── - // If the merge only brought in .storkit/ files (pipeline file moves), + // If the merge only brought in .huskies/ files (pipeline file moves), // there are no actual code changes to land on master. Abort. { let diff_check = Command::new("git") @@ -247,10 +247,10 @@ pub(crate) fn run_squash_merge( .output() .map_err(|e| format!("Failed to check merge diff: {e}"))?; let changed_files = String::from_utf8_lossy(&diff_check.stdout); - let has_code_changes = changed_files.lines().any(|f| !f.starts_with(".storkit/work/")); + let has_code_changes = changed_files.lines().any(|f| !f.starts_with(".huskies/work/")); if !has_code_changes { all_output.push_str( - "=== Merge commit contains only .storkit/ file moves, no code changes ===\n", + "=== Merge commit contains only .huskies/ file moves, no code changes ===\n", ); cleanup_merge_workspace(project_root, &merge_wt_path, &merge_branch); return Ok(SquashMergeResult { @@ -258,7 +258,7 @@ pub(crate) fn run_squash_merge( had_conflicts, conflicts_resolved, conflict_details: Some( - "Feature branch has no code changes outside .storkit/ — only \ + "Feature branch has no code changes outside .huskies/ — only \ pipeline file moves were found." .to_string(), ), @@ -419,10 +419,10 @@ pub(crate) fn run_squash_merge( } // Verify HEAD commit has actual code changes (not an empty cherry-pick). - // Exclude .storkit/work/ (pipeline file moves) but keep .storkit/project.toml + // Exclude .huskies/work/ (pipeline file moves) but keep .huskies/project.toml // and other config files which are legitimate deliverables. let diff_stat = Command::new("git") - .args(["diff", "--stat", "HEAD~1..HEAD", "--", ".", ":(exclude).storkit/work"]) + .args(["diff", "--stat", "HEAD~1..HEAD", "--", ".", ":(exclude).huskies/work"]) .current_dir(project_root) .output() .map(|o| String::from_utf8_lossy(&o.stdout).trim().to_string()) @@ -1047,7 +1047,7 @@ after\n"; // Verify no leftover merge workspace directory. assert!( - !repo.join(".storkit/merge_workspace").exists(), + !repo.join(".huskies/merge_workspace").exists(), "merge workspace should be cleaned up" ); } @@ -1167,7 +1167,7 @@ after\n"; .current_dir(repo) .output() .unwrap(); - let sk_dir = repo.join(".storkit/work/4_merge"); + let sk_dir = repo.join(".huskies/work/4_merge"); fs::create_dir_all(&sk_dir).unwrap(); fs::write(sk_dir.join("diverge_test.md"), "---\nname: test\n---\n").unwrap(); Command::new("git") @@ -1176,7 +1176,7 @@ after\n"; .output() .unwrap(); Command::new("git") - .args(["commit", "-m", "storkit: queue diverge_test for merge"]) + .args(["commit", "-m", "huskies: queue diverge_test for merge"]) .current_dir(repo) .output() .unwrap(); @@ -1218,7 +1218,7 @@ after\n"; "merge-queue branch should be cleaned up, got: {branch_list}" ); assert!( - !repo.join(".storkit/merge_workspace").exists(), + !repo.join(".huskies/merge_workspace").exists(), "merge workspace should be cleaned up" ); } @@ -1270,13 +1270,13 @@ after\n"; // Cleanup should still happen. assert!( - !repo.join(".storkit/merge_workspace").exists(), + !repo.join(".huskies/merge_workspace").exists(), "merge workspace should be cleaned up" ); } /// Bug 226: Verifies that `run_squash_merge` fails when the feature branch - /// only contains .storkit/ file moves with no real code changes. + /// only contains .huskies/ file moves with no real code changes. #[tokio::test] async fn squash_merge_md_only_changes_fails() { use std::fs; @@ -1286,13 +1286,13 @@ after\n"; let repo = tmp.path(); init_git_repo(repo); - // Create a feature branch that only moves a .storkit/ file. + // Create a feature branch that only moves a .huskies/ file. Command::new("git") .args(["checkout", "-b", "feature/story-md_only_test"]) .current_dir(repo) .output() .unwrap(); - let sk_dir = repo.join(".storkit/work/2_current"); + let sk_dir = repo.join(".huskies/work/2_current"); fs::create_dir_all(&sk_dir).unwrap(); fs::write(sk_dir.join("md_only_test.md"), "---\nname: Test\n---\n").unwrap(); Command::new("git") @@ -1313,17 +1313,17 @@ after\n"; let result = run_squash_merge(repo, "feature/story-md_only_test", "md_only_test").unwrap(); - // The squash merge will commit the .storkit/ file, but should fail because - // there are no code changes outside .storkit/. + // The squash merge will commit the .huskies/ file, but should fail because + // there are no code changes outside .huskies/. assert!( !result.success, - "merge with only .storkit/ changes must fail: {}", + "merge with only .huskies/ changes must fail: {}", result.output ); // Cleanup should still happen. assert!( - !repo.join(".storkit/merge_workspace").exists(), + !repo.join(".huskies/merge_workspace").exists(), "merge workspace should be cleaned up" ); } @@ -1444,7 +1444,7 @@ after\n"; "merge-queue branch must be cleaned up" ); assert!( - !repo.join(".storkit/merge_workspace").exists(), + !repo.join(".huskies/merge_workspace").exists(), "merge workspace must be cleaned up" ); } @@ -1560,7 +1560,7 @@ after\n"; // Cleanup must still happen. assert!( - !repo.join(".storkit/merge_workspace").exists(), + !repo.join(".huskies/merge_workspace").exists(), "merge workspace must be cleaned up even on gate failure" ); } @@ -1600,7 +1600,7 @@ after\n"; .unwrap(); // Simulate a stale merge workspace left from a previous failed merge. - let stale_ws = repo.join(".storkit/merge_workspace"); + let stale_ws = repo.join(".huskies/merge_workspace"); fs::create_dir_all(&stale_ws).unwrap(); fs::write(stale_ws.join("leftover.txt"), "stale").unwrap(); @@ -1620,7 +1620,7 @@ after\n"; // ── story 216: merge worktree uses project.toml component setup ─────────── - /// When the project has `[[component]]` entries in `.storkit/project.toml`, + /// When the project has `[[component]]` entries in `.huskies/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)] @@ -1633,9 +1633,9 @@ after\n"; let repo = tmp.path(); init_git_repo(repo); - // Add a .storkit/project.toml with a component whose setup writes a + // Add a .huskies/project.toml with a component whose setup writes a // sentinel file so we can confirm the command ran. - let sk_dir = repo.join(".storkit"); + let sk_dir = repo.join(".huskies"); fs::create_dir_all(&sk_dir).unwrap(); fs::write( sk_dir.join("project.toml"), @@ -1708,7 +1708,7 @@ after\n"; let repo = tmp.path(); init_git_repo(repo); - // No .storkit/project.toml — no component setup. + // No .huskies/project.toml — no component setup. fs::write(repo.join("file.txt"), "initial").unwrap(); Command::new("git") .args(["add", "."]) diff --git a/server/src/agents/pool/auto_assign/auto_assign.rs b/server/src/agents/pool/auto_assign/auto_assign.rs index 3107061c..ca49c81a 100644 --- a/server/src/agents/pool/auto_assign/auto_assign.rs +++ b/server/src/agents/pool/auto_assign/auto_assign.rs @@ -73,7 +73,7 @@ impl AgentPool { on feature branch. Writing merge_failure and blocking." ); let story_path = project_root - .join(".storkit/work") + .join(".huskies/work") .join(stage_dir) .join(format!("{story_id}.md")); let empty_diff_reason = "Feature branch has no code changes — the coder agent \ @@ -221,7 +221,7 @@ mod tests { #[tokio::test] async fn auto_assign_picks_up_story_queued_in_current() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); let current = sk.join("work/2_current"); std::fs::create_dir_all(¤t).unwrap(); std::fs::write( @@ -260,7 +260,7 @@ mod tests { let root = tmp.path(); // Create project.toml with a QA agent. - let sk = root.join(".storkit"); + let sk = root.join(".huskies"); std::fs::create_dir_all(&sk).unwrap(); std::fs::write( sk.join("project.toml"), @@ -269,7 +269,7 @@ mod tests { .unwrap(); // Put a spike in 3_qa/ with review_hold: true. - let qa_dir = root.join(".storkit/work/3_qa"); + let qa_dir = root.join(".huskies/work/3_qa"); std::fs::create_dir_all(&qa_dir).unwrap(); std::fs::write( qa_dir.join("20_spike_test.md"), @@ -298,7 +298,7 @@ mod tests { #[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(".storkit"); + let sk = tmp.path().join(".huskies"); let qa_dir = sk.join("work/3_qa"); std::fs::create_dir_all(&qa_dir).unwrap(); std::fs::write( @@ -345,7 +345,7 @@ mod tests { #[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(".storkit"); + let sk = tmp.path().join(".huskies"); let current_dir = sk.join("work/2_current"); std::fs::create_dir_all(¤t_dir).unwrap(); std::fs::write( @@ -392,7 +392,7 @@ mod tests { #[tokio::test] async fn auto_assign_stage_mismatch_with_no_fallback_starts_no_agent() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); 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. @@ -431,7 +431,7 @@ mod tests { let tmp = tempfile::tempdir().unwrap(); let root = tmp.path().to_path_buf(); - let sk_dir = root.join(".storkit"); + let sk_dir = root.join(".huskies"); // Two stories waiting in 2_current, one coder agent. fs::create_dir_all(sk_dir.join("work/2_current")).unwrap(); fs::write( diff --git a/server/src/agents/pool/auto_assign/reconcile.rs b/server/src/agents/pool/auto_assign/reconcile.rs index b12296d8..ec7f4284 100644 --- a/server/src/agents/pool/auto_assign/reconcile.rs +++ b/server/src/agents/pool/auto_assign/reconcile.rs @@ -18,7 +18,7 @@ impl AgentPool { /// (called immediately after) picks up the right next-stage agents. /// /// Algorithm: - /// 1. List all worktree directories under `{project_root}/.storkit/worktrees/`. + /// 1. List all worktree directories under `{project_root}/.huskies/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/`: @@ -153,7 +153,7 @@ impl AgentPool { .unwrap_or_default() .default_qa_mode(); let story_path = project_root - .join(".storkit/work/2_current") + .join(".huskies/work/2_current") .join(format!("{story_id}.md")); crate::io::story_metadata::resolve_qa_mode(&story_path, default_qa) } @@ -210,7 +210,7 @@ impl AgentPool { }); } else { let story_path = project_root - .join(".storkit/work/3_qa") + .join(".huskies/work/3_qa") .join(format!("{story_id}.md")); if let Err(e) = crate::io::story_metadata::write_review_hold(&story_path) @@ -268,7 +268,7 @@ impl AgentPool { true } else { let story_path = project_root - .join(".storkit/work/3_qa") + .join(".huskies/work/3_qa") .join(format!("{story_id}.md")); let default_qa = crate::config::ProjectConfig::load(project_root) .unwrap_or_default() @@ -282,7 +282,7 @@ impl AgentPool { if needs_human_review { let story_path = project_root - .join(".storkit/work/3_qa") + .join(".huskies/work/3_qa") .join(format!("{story_id}.md")); if let Err(e) = crate::io::story_metadata::write_review_hold(&story_path) @@ -416,13 +416,13 @@ mod tests { let root = tmp.path(); // Set up story in 2_current/. - let current = root.join(".storkit/work/2_current"); + let current = root.join(".huskies/work/2_current"); fs::create_dir_all(¤t).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(".storkit/worktrees/60_story_test"); + let wt_dir = root.join(".huskies/worktrees/60_story_test"); fs::create_dir_all(&wt_dir).unwrap(); init_git_repo(&wt_dir); @@ -447,7 +447,7 @@ mod tests { init_git_repo(root); // Set up story in 2_current/ and commit it so the project root is clean. - let current = root.join(".storkit/work/2_current"); + let current = root.join(".huskies/work/2_current"); fs::create_dir_all(¤t).unwrap(); fs::write(current.join("61_story_test.md"), "test").unwrap(); Command::new("git") @@ -470,7 +470,7 @@ mod tests { .unwrap(); // Create a real git worktree for the story. - let wt_dir = root.join(".storkit/worktrees/61_story_test"); + let wt_dir = root.join(".huskies/worktrees/61_story_test"); fs::create_dir_all(wt_dir.parent().unwrap()).unwrap(); Command::new("git") .args([ @@ -518,7 +518,7 @@ mod tests { // 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(".storkit/work/3_qa/61_story_test.md").exists(); + let in_qa = root.join(".huskies/work/3_qa/61_story_test.md").exists(); assert!( in_current || in_qa, "story should be in 2_current/ or 3_qa/ after reconciliation" diff --git a/server/src/agents/pool/auto_assign/scan.rs b/server/src/agents/pool/auto_assign/scan.rs index 24ffbc6b..901f710d 100644 --- a/server/src/agents/pool/auto_assign/scan.rs +++ b/server/src/agents/pool/auto_assign/scan.rs @@ -19,7 +19,7 @@ pub(in crate::agents::pool) fn is_agent_free( } pub(super) fn scan_stage_items(project_root: &Path, stage_dir: &str) -> Vec { - let dir = project_root.join(".storkit").join("work").join(stage_dir); + let dir = project_root.join(".huskies").join("work").join(stage_dir); if !dir.is_dir() { return Vec::new(); } @@ -169,7 +169,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(".storkit").join("work").join("2_current"); + let stage_dir = tmp.path().join(".huskies").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(); diff --git a/server/src/agents/pool/auto_assign/story_checks.rs b/server/src/agents/pool/auto_assign/story_checks.rs index f5133f2b..0e73e0d5 100644 --- a/server/src/agents/pool/auto_assign/story_checks.rs +++ b/server/src/agents/pool/auto_assign/story_checks.rs @@ -13,7 +13,7 @@ pub(super) fn read_story_front_matter_agent( ) -> Option { use crate::io::story_metadata::parse_front_matter; let path = project_root - .join(".storkit") + .join(".huskies") .join("work") .join(stage_dir) .join(format!("{story_id}.md")); @@ -25,7 +25,7 @@ pub(super) fn read_story_front_matter_agent( pub(super) 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(".storkit") + .join(".huskies") .join("work") .join(stage_dir) .join(format!("{story_id}.md")); @@ -43,7 +43,7 @@ pub(super) fn has_review_hold(project_root: &Path, stage_dir: &str, story_id: &s pub(super) 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(".storkit") + .join(".huskies") .join("work") .join(stage_dir) .join(format!("{story_id}.md")); @@ -61,7 +61,7 @@ pub(super) fn is_story_blocked(project_root: &Path, stage_dir: &str, story_id: & pub(super) 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(".storkit") + .join(".huskies") .join("work") .join(stage_dir) .join(format!("{story_id}.md")); @@ -84,7 +84,7 @@ mod tests { #[test] fn has_review_hold_returns_true_when_set() { let tmp = tempfile::tempdir().unwrap(); - let qa_dir = tmp.path().join(".storkit/work/3_qa"); + let qa_dir = tmp.path().join(".huskies/work/3_qa"); std::fs::create_dir_all(&qa_dir).unwrap(); let spike_path = qa_dir.join("10_spike_research.md"); std::fs::write( @@ -98,7 +98,7 @@ mod tests { #[test] fn has_review_hold_returns_false_when_not_set() { let tmp = tempfile::tempdir().unwrap(); - let qa_dir = tmp.path().join(".storkit/work/3_qa"); + let qa_dir = tmp.path().join(".huskies/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(); diff --git a/server/src/agents/pool/lifecycle.rs b/server/src/agents/pool/lifecycle.rs index 6a14b3d0..76bd0bbb 100644 --- a/server/src/agents/pool/lifecycle.rs +++ b/server/src/agents/pool/lifecycle.rs @@ -87,7 +87,7 @@ impl AgentPool { let front_matter_agent: Option = if agent_name.is_none() { find_active_story_stage(project_root, story_id).and_then(|stage_dir| { let path = project_root - .join(".storkit") + .join(".huskies") .join("work") .join(stage_dir) .join(format!("{story_id}.md")); @@ -873,7 +873,7 @@ mod tests { #[tokio::test] async fn start_agent_auto_selects_second_coder_when_first_busy() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); std::fs::create_dir_all(&sk).unwrap(); std::fs::write( sk.join("project.toml"), @@ -919,7 +919,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(".storkit"); + let sk = tmp.path().join(".huskies"); std::fs::create_dir_all(&sk).unwrap(); std::fs::write( sk.join("project.toml"), @@ -951,7 +951,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(".storkit"); + let sk = tmp.path().join(".huskies"); let backlog = sk.join("work/1_backlog"); std::fs::create_dir_all(&backlog).unwrap(); std::fs::write( @@ -996,7 +996,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(".storkit"); + let sk = tmp.path().join(".huskies"); let current = sk.join("work/2_current"); std::fs::create_dir_all(¤t).unwrap(); std::fs::write( @@ -1023,7 +1023,7 @@ stage = "coder" #[tokio::test] async fn start_agent_explicit_name_unchanged_when_busy() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); std::fs::create_dir_all(&sk).unwrap(); std::fs::write( sk.join("project.toml"), @@ -1062,7 +1062,7 @@ stage = "coder" let tmp = tempfile::tempdir().unwrap(); let root = tmp.path(); - let sk_dir = root.join(".storkit"); + let sk_dir = root.join(".huskies"); fs::create_dir_all(&sk_dir).unwrap(); fs::write(sk_dir.join("project.toml"), "[[agent]]\nname = \"qa\"\n").unwrap(); @@ -1089,7 +1089,7 @@ stage = "coder" let tmp = tempfile::tempdir().unwrap(); let root = tmp.path(); - let sk_dir = root.join(".storkit"); + let sk_dir = root.join(".huskies"); fs::create_dir_all(&sk_dir).unwrap(); fs::write(sk_dir.join("project.toml"), "[[agent]]\nname = \"qa\"\n").unwrap(); @@ -1115,7 +1115,7 @@ stage = "coder" let tmp = tempfile::tempdir().unwrap(); let root = tmp.path(); - let sk_dir = root.join(".storkit"); + let sk_dir = root.join(".huskies"); fs::create_dir_all(&sk_dir).unwrap(); fs::write( sk_dir.join("project.toml"), @@ -1123,7 +1123,7 @@ stage = "coder" ) .unwrap(); - let upcoming = root.join(".storkit/work/1_backlog"); + let upcoming = root.join(".huskies/work/1_backlog"); fs::create_dir_all(&upcoming).unwrap(); fs::write(upcoming.join("50_story_test.md"), "---\nname: Test\n---\n").unwrap(); @@ -1181,7 +1181,7 @@ stage = "coder" let tmp = tempfile::tempdir().unwrap(); let root = tmp.path(); - let sk_dir = root.join(".storkit"); + let sk_dir = root.join(".huskies"); fs::create_dir_all(&sk_dir).unwrap(); fs::write(sk_dir.join("project.toml"), "[[agent]]\nname = \"qa\"\n").unwrap(); @@ -1207,7 +1207,7 @@ stage = "coder" let tmp = tempfile::tempdir().unwrap(); let root = tmp.path(); - let sk_dir = root.join(".storkit"); + let sk_dir = root.join(".huskies"); fs::create_dir_all(&sk_dir).unwrap(); fs::write( sk_dir.join("project.toml"), @@ -1238,20 +1238,20 @@ stage = "coder" let tmp = tempfile::tempdir().unwrap(); let root = tmp.path().to_path_buf(); - let sk_dir = root.join(".storkit"); + let sk_dir = root.join(".huskies"); fs::create_dir_all(sk_dir.join("work/1_backlog")).unwrap(); fs::write( - root.join(".storkit/project.toml"), + root.join(".huskies/project.toml"), "[[agent]]\nname = \"coder-1\"\n", ) .unwrap(); fs::write( - root.join(".storkit/work/1_backlog/86_story_foo.md"), + root.join(".huskies/work/1_backlog/86_story_foo.md"), "---\nname: Foo\n---\n", ) .unwrap(); fs::write( - root.join(".storkit/work/1_backlog/130_story_bar.md"), + root.join(".huskies/work/1_backlog/130_story_bar.md"), "---\nname: Bar\n---\n", ) .unwrap(); @@ -1303,7 +1303,7 @@ stage = "coder" let tmp = tempfile::tempdir().unwrap(); let root = tmp.path(); - let sk_dir = root.join(".storkit"); + let sk_dir = root.join(".huskies"); fs::create_dir_all(&sk_dir).unwrap(); fs::write( sk_dir.join("project.toml"), @@ -1340,7 +1340,7 @@ stage = "coder" let tmp = tempfile::tempdir().unwrap(); let root = tmp.path(); - let sk_dir = root.join(".storkit"); + let sk_dir = root.join(".huskies"); fs::create_dir_all(&sk_dir).unwrap(); fs::write( sk_dir.join("project.toml"), @@ -1372,15 +1372,15 @@ stage = "coder" let tmp = tempfile::tempdir().unwrap(); let root = tmp.path().to_path_buf(); - let sk_dir = root.join(".storkit"); + let sk_dir = root.join(".huskies"); fs::create_dir_all(sk_dir.join("work/2_current")).unwrap(); fs::write( - root.join(".storkit/project.toml"), + root.join(".huskies/project.toml"), "[[agent]]\nname = \"coder-1\"\n\n[[agent]]\nname = \"coder-2\"\n", ) .unwrap(); fs::write( - root.join(".storkit/work/2_current/42_story_foo.md"), + root.join(".huskies/work/2_current/42_story_foo.md"), "---\nname: Foo\n---\n", ) .unwrap(); @@ -1426,15 +1426,15 @@ stage = "coder" let tmp = tempfile::tempdir().unwrap(); let root = tmp.path(); - let sk_dir = root.join(".storkit"); + let sk_dir = root.join(".huskies"); fs::create_dir_all(sk_dir.join("work/1_backlog")).unwrap(); fs::write( - root.join(".storkit/project.toml"), + root.join(".huskies/project.toml"), "[[agent]]\nname = \"coder-1\"\n\n[[agent]]\nname = \"coder-2\"\n", ) .unwrap(); fs::write( - root.join(".storkit/work/1_backlog/99_story_baz.md"), + root.join(".huskies/work/1_backlog/99_story_baz.md"), "---\nname: Baz\n---\n", ) .unwrap(); @@ -1464,7 +1464,7 @@ stage = "coder" let tmp = tempfile::tempdir().unwrap(); let root = tmp.path(); - let sk_dir = root.join(".storkit"); + let sk_dir = root.join(".huskies"); fs::create_dir_all(sk_dir.join("work/2_current")).unwrap(); fs::write( sk_dir.join("project.toml"), @@ -1501,7 +1501,7 @@ stage = "coder" let tmp = tempfile::tempdir().unwrap(); let root = tmp.path(); - let sk_dir = root.join(".storkit"); + let sk_dir = root.join(".huskies"); fs::create_dir_all(sk_dir.join("work/3_qa")).unwrap(); fs::write( sk_dir.join("project.toml"), @@ -1538,7 +1538,7 @@ stage = "coder" let tmp = tempfile::tempdir().unwrap(); let root = tmp.path(); - let sk_dir = root.join(".storkit"); + let sk_dir = root.join(".huskies"); fs::create_dir_all(sk_dir.join("work/4_merge")).unwrap(); fs::write( sk_dir.join("project.toml"), @@ -1575,7 +1575,7 @@ stage = "coder" let tmp = tempfile::tempdir().unwrap(); let root = tmp.path(); - let sk_dir = root.join(".storkit"); + let sk_dir = root.join(".huskies"); fs::create_dir_all(sk_dir.join("work/2_current")).unwrap(); fs::write( sk_dir.join("project.toml"), @@ -1611,7 +1611,7 @@ stage = "coder" let tmp = tempfile::tempdir().unwrap(); let root = tmp.path(); - let sk_dir = root.join(".storkit"); + let sk_dir = root.join(".huskies"); fs::create_dir_all(sk_dir.join("work/4_merge")).unwrap(); fs::write( sk_dir.join("project.toml"), @@ -1674,7 +1674,7 @@ stage = "coder" #[tokio::test] async fn start_agent_honours_front_matter_agent_when_idle() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); let backlog = sk.join("work/1_backlog"); std::fs::create_dir_all(&backlog).unwrap(); std::fs::write( @@ -1730,7 +1730,7 @@ stage = "coder" #[tokio::test] async fn start_agent_returns_error_when_front_matter_agent_busy() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); let backlog = sk.join("work/1_backlog"); std::fs::create_dir_all(&backlog).unwrap(); std::fs::write( @@ -1781,7 +1781,7 @@ stage = "coder" let tmp = tempfile::tempdir().unwrap(); let root = tmp.path(); - let current = root.join(".storkit/work/2_current"); + let current = root.join(".huskies/work/2_current"); fs::create_dir_all(¤t).unwrap(); fs::write(current.join("60_story_cleanup.md"), "test").unwrap(); @@ -1804,7 +1804,7 @@ stage = "coder" assert_eq!(remaining[0].story_id, "61_story_other"); assert!( - root.join(".storkit/work/5_done/60_story_cleanup.md") + root.join(".huskies/work/5_done/60_story_cleanup.md") .exists() ); } diff --git a/server/src/agents/pool/pipeline/advance.rs b/server/src/agents/pool/pipeline/advance.rs index ab0b7a2b..cf3b1048 100644 --- a/server/src/agents/pool/pipeline/advance.rs +++ b/server/src/agents/pool/pipeline/advance.rs @@ -55,7 +55,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(".storkit/work/2_current") + .join(".huskies/work/2_current") .join(format!("{story_id}.md")); crate::io::story_metadata::resolve_qa_mode(&story_path, default_qa) } @@ -104,7 +104,7 @@ impl AgentPool { if let Err(e) = crate::agents::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(".storkit/work/3_qa"); + let qa_dir = project_root.join(".huskies/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) @@ -119,7 +119,7 @@ impl AgentPool { } else { // Increment retry count and check if blocked. let story_path = project_root - .join(".storkit/work/2_current") + .join(".huskies/work/2_current") .join(format!("{story_id}.md")); if let Some(reason) = should_block_story(&story_path, config.max_retries, story_id, "coder") { // Story has exceeded retry limit — do not restart. @@ -174,7 +174,7 @@ impl AgentPool { if item_type == "spike" { true // Spikes always need human review. } else { - let qa_dir = project_root.join(".storkit/work/3_qa"); + let qa_dir = project_root.join(".huskies/work/3_qa"); let story_path = qa_dir.join(format!("{story_id}.md")); let default_qa = config.default_qa_mode(); matches!( @@ -186,7 +186,7 @@ impl AgentPool { if needs_human_review { // Hold in 3_qa/ for human review. - let qa_dir = project_root.join(".storkit/work/3_qa"); + let qa_dir = project_root.join(".huskies/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) @@ -222,7 +222,7 @@ impl AgentPool { } } else { let story_path = project_root - .join(".storkit/work/3_qa") + .join(".huskies/work/3_qa") .join(format!("{story_id}.md")); if let Some(reason) = should_block_story(&story_path, config.max_retries, story_id, "qa-coverage") { // Story has exceeded retry limit — do not restart. @@ -250,7 +250,7 @@ impl AgentPool { } } else { let story_path = project_root - .join(".storkit/work/3_qa") + .join(".huskies/work/3_qa") .join(format!("{story_id}.md")); if let Some(reason) = should_block_story(&story_path, config.max_retries, story_id, "qa") { // Story has exceeded retry limit — do not restart. @@ -330,7 +330,7 @@ impl AgentPool { ); } else { let story_path = project_root - .join(".storkit/work/4_merge") + .join(".huskies/work/4_merge") .join(format!("{story_id}.md")); if let Some(reason) = should_block_story(&story_path, config.max_retries, story_id, "mergemaster") { // Story has exceeded retry limit — do not restart. @@ -469,7 +469,7 @@ mod tests { let root = tmp.path(); // Set up story in 2_current/ (no qa frontmatter → uses project default "server") - let current = root.join(".storkit/work/2_current"); + let current = root.join(".huskies/work/2_current"); fs::create_dir_all(¤t).unwrap(); fs::write(current.join("50_story_test.md"), "test").unwrap(); @@ -490,7 +490,7 @@ mod tests { // With default qa: server, story skips QA and goes straight to 4_merge/ assert!( - root.join(".storkit/work/4_merge/50_story_test.md") + root.join(".huskies/work/4_merge/50_story_test.md") .exists(), "story should be in 4_merge/" ); @@ -507,7 +507,7 @@ mod tests { let root = tmp.path(); // Set up story in 2_current/ with qa: agent frontmatter - let current = root.join(".storkit/work/2_current"); + let current = root.join(".huskies/work/2_current"); fs::create_dir_all(¤t).unwrap(); fs::write( current.join("50_story_test.md"), @@ -532,7 +532,7 @@ mod tests { // With qa: agent, story should move to 3_qa/ assert!( - root.join(".storkit/work/3_qa/50_story_test.md").exists(), + root.join(".huskies/work/3_qa/50_story_test.md").exists(), "story should be in 3_qa/" ); assert!( @@ -548,7 +548,7 @@ mod tests { let root = tmp.path(); // Set up story in 3_qa/ - let qa_dir = root.join(".storkit/work/3_qa"); + let qa_dir = root.join(".huskies/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( @@ -574,7 +574,7 @@ mod tests { // Story should have moved to 4_merge/ assert!( - root.join(".storkit/work/4_merge/51_story_test.md") + root.join(".huskies/work/4_merge/51_story_test.md") .exists(), "story should be in 4_merge/" ); @@ -590,7 +590,7 @@ mod tests { let tmp = tempfile::tempdir().unwrap(); let root = tmp.path(); - let current = root.join(".storkit/work/2_current"); + let current = root.join(".huskies/work/2_current"); fs::create_dir_all(¤t).unwrap(); fs::write(current.join("52_story_test.md"), "test").unwrap(); @@ -624,18 +624,18 @@ mod tests { let root = tmp.path(); // Set up story in 2_current/ - let current = root.join(".storkit/work/2_current"); + let current = root.join(".huskies/work/2_current"); fs::create_dir_all(¤t).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(".storkit/work/3_qa")).unwrap(); + fs::create_dir_all(root.join(".huskies/work/3_qa")).unwrap(); // Ensure 1_backlog/ exists (start_agent calls move_story_to_current) - fs::create_dir_all(root.join(".storkit/work/1_backlog")).unwrap(); + fs::create_dir_all(root.join(".huskies/work/1_backlog")).unwrap(); // Write a project.toml with a qa agent so start_agent can resolve it. - fs::create_dir_all(root.join(".storkit")).unwrap(); + fs::create_dir_all(root.join(".huskies")).unwrap(); fs::write( - root.join(".storkit/project.toml"), + root.join(".huskies/project.toml"), r#" default_qa = "agent" @@ -703,7 +703,7 @@ stage = "qa" let tmp = tempfile::tempdir().unwrap(); let root = tmp.path(); - let sk = root.join(".storkit"); + let sk = root.join(".huskies"); let qa_dir = sk.join("work/3_qa"); fs::create_dir_all(&qa_dir).unwrap(); diff --git a/server/src/agents/pool/pipeline/completion.rs b/server/src/agents/pool/pipeline/completion.rs index 70aef62d..38c314b7 100644 --- a/server/src/agents/pool/pipeline/completion.rs +++ b/server/src/agents/pool/pipeline/completion.rs @@ -563,7 +563,7 @@ mod tests { fs::set_permissions(&script_test, perms).unwrap(); // Story in 4_merge/ — must NOT be moved to 5_done/. - let merge_dir = root.join(".storkit/work/4_merge"); + let merge_dir = root.join(".huskies/work/4_merge"); fs::create_dir_all(&merge_dir).unwrap(); let story_path = merge_dir.join("99_story_merge445.md"); fs::write(&story_path, "---\nname: Merge 445 Test\n---\n").unwrap(); @@ -590,7 +590,7 @@ mod tests { tokio::time::sleep(std::time::Duration::from_millis(150)).await; // Story must remain in 4_merge/ — not moved to 5_done/. - let done_path = root.join(".storkit/work/5_done/99_story_merge445.md"); + let done_path = root.join(".huskies/work/5_done/99_story_merge445.md"); assert!( !done_path.exists(), "Story must NOT be moved to 5_done/ when run_server_owned_completion \ diff --git a/server/src/agents/pool/pipeline/merge.rs b/server/src/agents/pool/pipeline/merge.rs index 82a697cd..f482c5a5 100644 --- a/server/src/agents/pool/pipeline/merge.rs +++ b/server/src/agents/pool/pipeline/merge.rs @@ -289,7 +289,7 @@ mod tests { .unwrap(); // Create the story file in 4_merge/ so we can test archival - let merge_dir = repo.join(".storkit/work/4_merge"); + let merge_dir = repo.join(".huskies/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(); @@ -317,7 +317,7 @@ mod tests { "report should be coherent: {report:?}" ); if report.story_archived { - let done = repo.join(".storkit/work/5_done/23_test.md"); + let done = repo.join(".huskies/work/5_done/23_test.md"); assert!(done.exists(), "done file should exist"); } } @@ -502,7 +502,7 @@ mod tests { .unwrap(); // Create story file in 4_merge. - let merge_dir = repo.join(".storkit/work/4_merge"); + let merge_dir = repo.join(".huskies/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") diff --git a/server/src/agents/pool/worktree.rs b/server/src/agents/pool/worktree.rs index c118481f..fab2a295 100644 --- a/server/src/agents/pool/worktree.rs +++ b/server/src/agents/pool/worktree.rs @@ -26,7 +26,7 @@ pub(super) fn find_active_story_stage(project_root: &Path, story_id: &str) -> Op const STAGES: [&str; 3] = ["2_current", "3_qa", "4_merge"]; for stage in &STAGES { let path = project_root - .join(".storkit") + .join(".huskies") .join("work") .join(stage) .join(format!("{story_id}.md")); @@ -46,7 +46,7 @@ mod tests { use std::fs; let tmp = tempfile::tempdir().unwrap(); let root = tmp.path(); - let current = root.join(".storkit/work/2_current"); + let current = root.join(".huskies/work/2_current"); fs::create_dir_all(¤t).unwrap(); fs::write(current.join("10_story_test.md"), "test").unwrap(); @@ -61,7 +61,7 @@ mod tests { use std::fs; let tmp = tempfile::tempdir().unwrap(); let root = tmp.path(); - let qa = root.join(".storkit/work/3_qa"); + let qa = root.join(".huskies/work/3_qa"); fs::create_dir_all(&qa).unwrap(); fs::write(qa.join("11_story_test.md"), "test").unwrap(); @@ -73,7 +73,7 @@ mod tests { use std::fs; let tmp = tempfile::tempdir().unwrap(); let root = tmp.path(); - let merge = root.join(".storkit/work/4_merge"); + let merge = root.join(".huskies/work/4_merge"); fs::create_dir_all(&merge).unwrap(); fs::write(merge.join("12_story_test.md"), "test").unwrap(); diff --git a/server/src/agents/runtime/gemini.rs b/server/src/agents/runtime/gemini.rs index cd560003..9792dc84 100644 --- a/server/src/agents/runtime/gemini.rs +++ b/server/src/agents/runtime/gemini.rs @@ -18,7 +18,7 @@ use super::{AgentRuntime, RuntimeContext, RuntimeResult, RuntimeStatus}; /// `generateContent` REST API. /// /// The runtime: -/// 1. Fetches MCP tool definitions from storkit's MCP server. +/// 1. Fetches MCP tool definitions from huskies' MCP server. /// 2. Converts them to Gemini function-calling format. /// 3. Sends the agent prompt + tools to the Gemini API. /// 4. Executes any requested function calls via MCP `tools/call`. @@ -401,7 +401,7 @@ fn build_generate_content_request( body } -/// Fetch MCP tool definitions from storkit's MCP server and convert +/// Fetch MCP tool definitions from huskies' MCP server and convert /// them to Gemini function declaration format. async fn fetch_and_convert_mcp_tools( client: &Client, @@ -522,7 +522,7 @@ fn clean_schema_properties(properties: &Value) -> Value { Value::Object(cleaned) } -/// Call an MCP tool via storkit's MCP server. +/// Call an MCP tool via huskies' MCP server. async fn call_mcp_tool( client: &Client, mcp_base: &str, diff --git a/server/src/agents/runtime/mod.rs b/server/src/agents/runtime/mod.rs index db184353..5fa2bab0 100644 --- a/server/src/agents/runtime/mod.rs +++ b/server/src/agents/runtime/mod.rs @@ -22,7 +22,7 @@ pub struct RuntimeContext { pub prompt: String, pub cwd: String, pub inactivity_timeout_secs: u64, - /// Port of the storkit MCP server, used by API-based runtimes (Gemini, OpenAI) + /// Port of the huskies MCP server, used by API-based runtimes (Gemini, OpenAI) /// to call back for tool execution. pub mcp_port: u16, } diff --git a/server/src/agents/runtime/openai.rs b/server/src/agents/runtime/openai.rs index b7ecdad2..89e2a39e 100644 --- a/server/src/agents/runtime/openai.rs +++ b/server/src/agents/runtime/openai.rs @@ -17,7 +17,7 @@ use super::{AgentRuntime, RuntimeContext, RuntimeResult, RuntimeStatus}; /// the OpenAI Chat Completions API. /// /// The runtime: -/// 1. Fetches MCP tool definitions from storkit's MCP server. +/// 1. Fetches MCP tool definitions from huskies' MCP server. /// 2. Converts them to OpenAI function-calling format. /// 3. Sends the agent prompt + tools to the Chat Completions API. /// 4. Executes any requested tool calls via MCP `tools/call`. @@ -311,7 +311,7 @@ fn build_system_text(ctx: &RuntimeContext) -> String { }) } -/// Fetch MCP tool definitions from storkit's MCP server and convert +/// Fetch MCP tool definitions from huskies' MCP server and convert /// them to OpenAI function-calling format. async fn fetch_and_convert_mcp_tools( client: &Client, @@ -433,7 +433,7 @@ fn clean_schema_properties(properties: &Value) -> Value { Value::Object(cleaned) } -/// Call an MCP tool via storkit's MCP server. +/// Call an MCP tool via huskies' MCP server. async fn call_mcp_tool( client: &Client, mcp_base: &str, diff --git a/server/src/agents/token_usage.rs b/server/src/agents/token_usage.rs index 74c7a7c9..18a50898 100644 --- a/server/src/agents/token_usage.rs +++ b/server/src/agents/token_usage.rs @@ -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 `.storkit/token_usage.jsonl`. +/// reads simple. The file lives at `.huskies/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(".storkit").join("token_usage.jsonl") + project_root.join(".huskies").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(".storkit").join("token_usage.jsonl"); + let path = root.join(".huskies").join("token_usage.jsonl"); fs::create_dir_all(path.parent().unwrap()).unwrap(); fs::write(&path, "not json\n{\"bad\":true}\n").unwrap(); diff --git a/server/src/chat/commands/loc.rs b/server/src/chat/commands/loc.rs index a56d0a5a..176eb142 100644 --- a/server/src/chat/commands/loc.rs +++ b/server/src/chat/commands/loc.rs @@ -18,7 +18,7 @@ const SKIP_DIRS: &[&str] = &[ ]; /// Path components that indicate a worktree path that should be skipped. -const SKIP_PATH_COMPONENTS: &[&str] = &[".storkit/worktrees"]; +const SKIP_PATH_COMPONENTS: &[&str] = &[".huskies/worktrees"]; /// Known-huge or machine-generated files that are excluded from the loc count /// even when they have a recognised source extension (e.g. `.json`, `.yaml`). @@ -88,10 +88,10 @@ fn loc_top_n(project_root: &std::path::Path, top_n: usize) -> String { if SKIP_DIRS.iter().any(|s| *s == name.as_ref()) { return false; } - // Skip .storkit/worktrees — use relative path so the check + // Skip .huskies/worktrees — use relative path so the check // doesn't exclude the project root itself when running // from inside a worktree (where the absolute path contains - // ".storkit/worktrees"). + // ".huskies/worktrees"). let rel = e .path() .strip_prefix(project_root) @@ -332,7 +332,7 @@ mod tests { let ctx = make_ctx(&agents, &ambient_rooms, repo_root, ""); let output = handle_loc(&ctx).unwrap(); assert!( - !output.contains(".storkit/worktrees"), + !output.contains(".huskies/worktrees"), "output must not include paths inside worktrees: {output}" ); } diff --git a/server/src/chat/commands/move_story.rs b/server/src/chat/commands/move_story.rs index 65d6f3ac..a523f3ec 100644 --- a/server/src/chat/commands/move_story.rs +++ b/server/src/chat/commands/move_story.rs @@ -62,7 +62,7 @@ pub(super) fn handle_move(ctx: &CommandContext) -> Option { 'outer: for stage_dir in SEARCH_DIRS { let dir = ctx .project_root - .join(".storkit") + .join(".huskies") .join("work") .join(stage_dir); if !dir.exists() { @@ -242,7 +242,7 @@ mod tests { // Verify the file was actually moved. let new_path = tmp .path() - .join(".storkit/work/2_current/42_story_some_feature.md"); + .join(".huskies/work/2_current/42_story_some_feature.md"); assert!(new_path.exists(), "story file should be in 2_current/"); } diff --git a/server/src/chat/commands/overview.rs b/server/src/chat/commands/overview.rs index 1c691293..d897d832 100644 --- a/server/src/chat/commands/overview.rs +++ b/server/src/chat/commands/overview.rs @@ -4,7 +4,7 @@ use super::CommandContext; /// Show implementation summary for a story identified by its number. /// -/// Finds the `storkit: merge {story_id}` commit on master, displays the +/// Finds the `huskies: merge {story_id}` commit on master, displays the /// git diff --stat (files changed with line counts), and extracts key /// function/struct/type names added or modified in the implementation. /// Returns a friendly message when no merge commit is found. @@ -82,11 +82,11 @@ pub(super) fn handle_overview(ctx: &CommandContext) -> Option { /// Find the merge commit hash for a story by its numeric ID. /// /// Searches git log for a commit whose subject matches -/// `storkit: merge {num}_*` or the legacy `story-kit: merge {num}_*`. +/// `huskies: merge {num}_*` or the legacy `story-kit: merge {num}_*`. fn find_story_merge_commit(root: &std::path::Path, num_str: &str) -> Option { use std::process::Command; // Match both the current prefix and the legacy one from before the rename. - let grep_pattern = format!("(storkit|story-kit): merge {num_str}_"); + let grep_pattern = format!("(huskies|storkit|story-kit): merge {num_str}_"); let output = Command::new("git") .args([ "log", @@ -116,7 +116,7 @@ fn find_story_name(root: &std::path::Path, num_str: &str) -> Option { "6_archived", ]; for stage in &stages { - let dir = root.join(".storkit").join("work").join(stage); + let dir = root.join(".huskies").join("work").join(stage); if !dir.exists() { continue; } diff --git a/server/src/chat/commands/setup.rs b/server/src/chat/commands/setup.rs index 74e75a18..31f89080 100644 --- a/server/src/chat/commands/setup.rs +++ b/server/src/chat/commands/setup.rs @@ -63,7 +63,7 @@ fn wizard_status_reply(ctx: &CommandContext) -> String { match WizardState::load(ctx.project_root) { Some(state) => format_wizard_state(&state), None => { - "No setup wizard active. Run `storkit init` in the project root to begin.".to_string() + "No setup wizard active. Run `huskies init` in the project root to begin.".to_string() } } } @@ -215,13 +215,13 @@ mod tests { let rooms = Arc::new(Mutex::new(HashSet::new())); let ctx = make_ctx("", dir.path(), &agents, &rooms); let result = handle_setup(&ctx).unwrap(); - assert!(result.contains("storkit init")); + assert!(result.contains("huskies init")); } #[test] fn setup_with_wizard_shows_status() { 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(); WizardState::init_if_missing(dir.path()); let agents = Arc::new(crate::agents::AgentPool::new_test(4001)); let rooms = Arc::new(Mutex::new(HashSet::new())); @@ -233,7 +233,7 @@ mod tests { #[test] fn setup_skip_advances_wizard() { 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(); WizardState::init_if_missing(dir.path()); let agents = Arc::new(crate::agents::AgentPool::new_test(4002)); let rooms = Arc::new(Mutex::new(HashSet::new())); @@ -247,7 +247,7 @@ mod tests { #[test] fn setup_confirm_advances_wizard() { 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(); WizardState::init_if_missing(dir.path()); let agents = Arc::new(crate::agents::AgentPool::new_test(4003)); let rooms = Arc::new(Mutex::new(HashSet::new())); @@ -261,7 +261,7 @@ mod tests { #[test] fn setup_retry_resets_step() { 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(); WizardState::init_if_missing(dir.path()); // Stage some content first. { @@ -299,7 +299,7 @@ mod tests { #[test] fn setup_generate_marks_generating_and_returns_hint() { 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(); WizardState::init_if_missing(dir.path()); let agents = Arc::new(crate::agents::AgentPool::new_test(4006)); let rooms = Arc::new(Mutex::new(HashSet::new())); @@ -317,7 +317,7 @@ mod tests { fn setup_generate_bare_project_asks_user() { let dir = TempDir::new().unwrap(); // Bare project — only scaffolding files - std::fs::create_dir_all(dir.path().join(".storkit")).unwrap(); + std::fs::create_dir_all(dir.path().join(".huskies")).unwrap(); WizardState::init_if_missing(dir.path()); let agents = Arc::new(crate::agents::AgentPool::new_test(4007)); let rooms = Arc::new(Mutex::new(HashSet::new())); diff --git a/server/src/chat/commands/show.rs b/server/src/chat/commands/show.rs index 20293763..6b424f2d 100644 --- a/server/src/chat/commands/show.rs +++ b/server/src/chat/commands/show.rs @@ -34,7 +34,7 @@ pub(super) fn handle_show(ctx: &CommandContext) -> Option { for stage in &stages { let dir = ctx .project_root - .join(".storkit") + .join(".huskies") .join("work") .join(stage); if !dir.exists() { diff --git a/server/src/chat/commands/status.rs b/server/src/chat/commands/status.rs index 138b2e43..b9924d27 100644 --- a/server/src/chat/commands/status.rs +++ b/server/src/chat/commands/status.rs @@ -54,7 +54,7 @@ pub(super) fn story_short_label(stem: &str, name: Option<&str>) -> String { /// Returns `true` when the story has `blocked: true` set (retry limit reached). fn read_story_blocked(project_root: &std::path::Path, stage_dir: &str, stem: &str) -> bool { let path = project_root - .join(".storkit") + .join(".huskies") .join("work") .join(stage_dir) .join(format!("{stem}.md")); @@ -93,7 +93,7 @@ fn read_stage_items( stage_dir: &str, ) -> Vec<(String, Option)> { let dir = project_root - .join(".storkit") + .join(".huskies") .join("work") .join(stage_dir); if !dir.exists() { @@ -346,7 +346,7 @@ mod tests { use tempfile::TempDir; let tmp = TempDir::new().unwrap(); - let stage_dir = tmp.path().join(".storkit/work/2_current"); + let stage_dir = tmp.path().join(".huskies/work/2_current"); std::fs::create_dir_all(&stage_dir).unwrap(); // Write a story file with a front-matter name @@ -375,7 +375,7 @@ mod tests { use tempfile::TempDir; let tmp = TempDir::new().unwrap(); - let stage_dir = tmp.path().join(".storkit/work/2_current"); + let stage_dir = tmp.path().join(".huskies/work/2_current"); std::fs::create_dir_all(&stage_dir).unwrap(); let story_path = stage_dir.join("293_story_register_all_bot_commands.md"); @@ -413,7 +413,7 @@ mod tests { use tempfile::TempDir; let tmp = TempDir::new().unwrap(); - let stage_dir = tmp.path().join(".storkit/work/2_current"); + let stage_dir = tmp.path().join(".huskies/work/2_current"); std::fs::create_dir_all(&stage_dir).unwrap(); let story_path = stage_dir.join("293_story_register_all_bot_commands.md"); @@ -436,7 +436,7 @@ mod tests { use tempfile::TempDir; let tmp = TempDir::new().unwrap(); - let stage_dir = tmp.path().join(".storkit/work/2_current"); + let stage_dir = tmp.path().join(".huskies/work/2_current"); std::fs::create_dir_all(&stage_dir).unwrap(); let story_path = stage_dir.join("293_story_register_all_bot_commands.md"); @@ -480,7 +480,7 @@ mod tests { use tempfile::TempDir; let tmp = TempDir::new().unwrap(); - let stage_dir = tmp.path().join(".storkit/work/2_current"); + let stage_dir = tmp.path().join(".huskies/work/2_current"); std::fs::create_dir_all(&stage_dir).unwrap(); let story_path = stage_dir.join("42_story_idle.md"); @@ -502,7 +502,7 @@ mod tests { use tempfile::TempDir; let tmp = TempDir::new().unwrap(); - let stage_dir = tmp.path().join(".storkit/work/2_current"); + let stage_dir = tmp.path().join(".huskies/work/2_current"); std::fs::create_dir_all(&stage_dir).unwrap(); let story_path = stage_dir.join("42_story_blocked.md"); @@ -524,7 +524,7 @@ mod tests { use tempfile::TempDir; let tmp = TempDir::new().unwrap(); - let stage_dir = tmp.path().join(".storkit/work/2_current"); + let stage_dir = tmp.path().join(".huskies/work/2_current"); std::fs::create_dir_all(&stage_dir).unwrap(); let story_path = stage_dir.join("42_story_idle.md"); @@ -578,7 +578,7 @@ mod tests { fn read_story_blocked_returns_true_when_blocked() { use tempfile::TempDir; let tmp = TempDir::new().unwrap(); - let stage_dir = tmp.path().join(".storkit/work/2_current"); + let stage_dir = tmp.path().join(".huskies/work/2_current"); std::fs::create_dir_all(&stage_dir).unwrap(); std::fs::write( stage_dir.join("42_story_foo.md"), @@ -592,7 +592,7 @@ mod tests { fn read_story_blocked_returns_false_when_not_blocked() { use tempfile::TempDir; let tmp = TempDir::new().unwrap(); - let stage_dir = tmp.path().join(".storkit/work/2_current"); + let stage_dir = tmp.path().join(".huskies/work/2_current"); std::fs::create_dir_all(&stage_dir).unwrap(); std::fs::write( stage_dir.join("42_story_foo.md"), @@ -610,7 +610,7 @@ mod tests { use tempfile::TempDir; let tmp = TempDir::new().unwrap(); - let stage_dir = tmp.path().join(".storkit/work/2_current"); + let stage_dir = tmp.path().join(".huskies/work/2_current"); std::fs::create_dir_all(&stage_dir).unwrap(); let story_path = stage_dir.join("42_story_idle.md"); @@ -632,7 +632,7 @@ mod tests { use tempfile::TempDir; let tmp = TempDir::new().unwrap(); - let stage_dir = tmp.path().join(".storkit/work/2_current"); + let stage_dir = tmp.path().join(".huskies/work/2_current"); std::fs::create_dir_all(&stage_dir).unwrap(); let story_path = stage_dir.join("42_story_blocked.md"); diff --git a/server/src/chat/commands/triage.rs b/server/src/chat/commands/triage.rs index 37e78ca9..0195d837 100644 --- a/server/src/chat/commands/triage.rs +++ b/server/src/chat/commands/triage.rs @@ -28,7 +28,7 @@ pub(super) fn handle_triage(ctx: &CommandContext) -> Option { let current_dir = ctx .project_root - .join(".storkit") + .join(".huskies") .join("work") .join("2_current"); @@ -179,7 +179,7 @@ fn build_triage_dump( // ---- Agent log tail ---- let log_dir = ctx .project_root - .join(".storkit") + .join(".huskies") .join("logs") .join(story_id); match latest_log_file(&log_dir) { diff --git a/server/src/chat/commands/unblock.rs b/server/src/chat/commands/unblock.rs index d3d40fa8..956ec7fe 100644 --- a/server/src/chat/commands/unblock.rs +++ b/server/src/chat/commands/unblock.rs @@ -45,7 +45,7 @@ pub(crate) fn unblock_by_number(project_root: &Path, story_number: &str) -> Stri let mut found: Option<(std::path::PathBuf, String)> = None; 'outer: for stage_dir in SEARCH_DIRS { - let dir = project_root.join(".storkit").join("work").join(stage_dir); + let dir = project_root.join(".huskies").join("work").join(stage_dir); if !dir.exists() { continue; } @@ -252,7 +252,7 @@ mod tests { ); let contents = std::fs::read_to_string( - tmp.path().join(".storkit/work/2_current/7_story_stuck.md"), + tmp.path().join(".huskies/work/2_current/7_story_stuck.md"), ) .unwrap(); assert!( diff --git a/server/src/chat/commands/unreleased.rs b/server/src/chat/commands/unreleased.rs index bec4376c..97ac5d39 100644 --- a/server/src/chat/commands/unreleased.rs +++ b/server/src/chat/commands/unreleased.rs @@ -77,7 +77,7 @@ fn find_last_release_tag(root: &std::path::Path) -> Option { if tag.is_empty() { None } else { Some(tag) } } -/// Return the subjects of all `storkit: merge …` commits reachable from HEAD +/// Return the subjects of all `huskies: merge …` commits reachable from HEAD /// but not from `since_tag` (or all commits when `since_tag` is `None`). fn list_merge_commits_since( root: &std::path::Path, @@ -97,7 +97,7 @@ fn list_merge_commits_since( "--format=%s", "--extended-regexp", "--grep", - "(storkit|story-kit): merge [0-9]+_", + "(huskies|storkit|story-kit): merge [0-9]+_", ]) .current_dir(root) .output() @@ -115,14 +115,14 @@ fn list_merge_commits_since( } /// Parse a story number and slug from a merge commit subject like -/// `storkit: merge 386_story_unreleased_command`. +/// `huskies: merge 386_story_unreleased_command`. /// /// Returns `(story_number, slug_remainder)` or `None` if the subject doesn't /// match the expected pattern. fn parse_story_from_subject(subject: &str) -> Option<(u64, String)> { - // Match "storkit: merge NNN_rest" or "story-kit: merge NNN_rest" + // Match "huskies: merge NNN_rest" or "story-kit: merge NNN_rest" let rest = subject - .strip_prefix("storkit: merge ") + .strip_prefix("huskies: merge ") .or_else(|| subject.strip_prefix("story-kit: merge "))?; let (num_str, slug) = rest.split_once('_')?; @@ -159,7 +159,7 @@ fn find_story_name(root: &std::path::Path, num_str: &str) -> Option { "6_archived", ]; for stage in STAGES { - let dir = root.join(".storkit").join("work").join(stage); + let dir = root.join(".huskies").join("work").join(stage); if !dir.exists() { continue; } @@ -271,8 +271,8 @@ mod tests { // -- parse_story_from_subject ------------------------------------------ #[test] - fn parse_story_storkit_prefix() { - let result = parse_story_from_subject("storkit: merge 386_story_unreleased_command"); + fn parse_story_huskies_prefix() { + let result = parse_story_from_subject("huskies: merge 386_story_unreleased_command"); assert_eq!(result, Some((386, "story_unreleased_command".to_string()))); } @@ -290,7 +290,7 @@ mod tests { #[test] fn parse_story_no_underscore_after_number() { - let result = parse_story_from_subject("storkit: merge 123"); + let result = parse_story_from_subject("huskies: merge 123"); assert_eq!(result, None); } diff --git a/server/src/chat/test_helpers.rs b/server/src/chat/test_helpers.rs index 8ae5f170..2ed47f52 100644 --- a/server/src/chat/test_helpers.rs +++ b/server/src/chat/test_helpers.rs @@ -6,10 +6,10 @@ use std::path::Path; /// Write a work-item file into the standard pipeline directory structure. /// -/// Creates `.storkit/work/{stage}/{filename}` under `root`, creating any +/// Creates `.huskies/work/{stage}/{filename}` under `root`, creating any /// missing parent directories. pub(crate) fn write_story_file(root: &Path, stage: &str, filename: &str, content: &str) { - let dir = root.join(".storkit/work").join(stage); + let dir = root.join(".huskies/work").join(stage); std::fs::create_dir_all(&dir).unwrap(); std::fs::write(dir.join(filename), content).unwrap(); } diff --git a/server/src/chat/timer.rs b/server/src/chat/timer.rs index 44a47550..2ae55273 100644 --- a/server/src/chat/timer.rs +++ b/server/src/chat/timer.rs @@ -1,6 +1,6 @@ //! Deferred agent start via one-shot timers. //! -//! Provides [`TimerStore`] for persisting timers to `.storkit/timers.json`, +//! Provides [`TimerStore`] for persisting timers to `.huskies/timers.json`, //! a 30-second tick loop ([`spawn_timer_tick_loop`]) that fires due timers, //! and command parsing / handling for the `timer` bot command. @@ -398,7 +398,7 @@ pub async fn handle_timer_command( // The story must be in backlog or current. When the timer fires, // backlog stories are moved to current automatically. - let work_dir = project_root.join(".storkit").join("work"); + let work_dir = project_root.join(".huskies").join("work"); let in_backlog = work_dir.join("1_backlog").join(format!("{story_id}.md")).exists(); let in_current = work_dir.join("2_current").join(format!("{story_id}.md")).exists(); if !in_backlog && !in_current { @@ -555,7 +555,7 @@ fn resolve_story_id(number_or_id: &str, project_root: &Path) -> Option { } for stage in STAGES { - let dir = project_root.join(".storkit").join("work").join(stage); + let dir = project_root.join(".huskies").join("work").join(stage); if !dir.exists() { continue; } @@ -931,8 +931,8 @@ mod tests { async fn handle_schedule_story_not_in_backlog_or_current() { let dir = TempDir::new().unwrap(); // Set up directory structure with no story in backlog or current - std::fs::create_dir_all(dir.path().join(".storkit/work/1_backlog")).unwrap(); - std::fs::create_dir_all(dir.path().join(".storkit/work/2_current")).unwrap(); + std::fs::create_dir_all(dir.path().join(".huskies/work/1_backlog")).unwrap(); + std::fs::create_dir_all(dir.path().join(".huskies/work/2_current")).unwrap(); let store = TimerStore::load(dir.path().join("timers.json")); let result = handle_timer_command( TimerCommand::Schedule { @@ -952,7 +952,7 @@ mod tests { #[tokio::test] async fn handle_schedule_accepts_backlog_story() { let dir = TempDir::new().unwrap(); - let backlog_dir = dir.path().join(".storkit/work/1_backlog"); + let backlog_dir = dir.path().join(".huskies/work/1_backlog"); std::fs::create_dir_all(&backlog_dir).unwrap(); std::fs::write( backlog_dir.join("421_story_foo.md"), @@ -978,7 +978,7 @@ mod tests { #[tokio::test] async fn handle_schedule_success() { let dir = TempDir::new().unwrap(); - let current_dir = dir.path().join(".storkit/work/2_current"); + let current_dir = dir.path().join(".huskies/work/2_current"); std::fs::create_dir_all(¤t_dir).unwrap(); std::fs::write(current_dir.join("421_story_foo.md"), "---\nname: Foo\n---").unwrap(); let store = TimerStore::load(dir.path().join("timers.json")); @@ -1001,7 +1001,7 @@ mod tests { #[tokio::test] async fn handle_schedule_invalid_time() { let dir = TempDir::new().unwrap(); - let current_dir = dir.path().join(".storkit/work/2_current"); + let current_dir = dir.path().join(".huskies/work/2_current"); std::fs::create_dir_all(¤t_dir).unwrap(); std::fs::write(current_dir.join("421_story_foo.md"), "---\nname: Foo\n---").unwrap(); let store = TimerStore::load(dir.path().join("timers.json")); @@ -1058,8 +1058,8 @@ mod tests { let dir = TempDir::new().unwrap(); let root = dir.path(); - let backlog = root.join(".storkit/work/1_backlog"); - let current = root.join(".storkit/work/2_current"); + let backlog = root.join(".huskies/work/1_backlog"); + let current = root.join(".huskies/work/2_current"); fs::create_dir_all(&backlog).unwrap(); fs::create_dir_all(¤t).unwrap(); fs::write(backlog.join("421_story_foo.md"), "---\nname: Foo\n---\n").unwrap(); @@ -1103,8 +1103,8 @@ mod tests { let dir = TempDir::new().unwrap(); let root = dir.path(); - let backlog = root.join(".storkit/work/1_backlog"); - let current = root.join(".storkit/work/2_current"); + let backlog = root.join(".huskies/work/1_backlog"); + let current = root.join(".huskies/work/2_current"); fs::create_dir_all(&backlog).unwrap(); fs::create_dir_all(¤t).unwrap(); fs::write( diff --git a/server/src/chat/transport/matrix/assign.rs b/server/src/chat/transport/matrix/assign.rs index 33d21b00..e07d4862 100644 --- a/server/src/chat/transport/matrix/assign.rs +++ b/server/src/chat/transport/matrix/assign.rs @@ -104,7 +104,7 @@ pub async fn handle_assign( // Find the story file across all pipeline stages. let mut found: Option<(std::path::PathBuf, String)> = None; 'outer: for stage in STAGES { - let dir = project_root.join(".storkit").join("work").join(stage); + let dir = project_root.join(".huskies").join("work").join(stage); if !dir.exists() { continue; } @@ -356,7 +356,7 @@ mod tests { async fn handle_assign_returns_not_found_for_unknown_number() { let tmp = tempfile::tempdir().unwrap(); for stage in STAGES { - std::fs::create_dir_all(tmp.path().join(".storkit/work").join(stage)).unwrap(); + std::fs::create_dir_all(tmp.path().join(".huskies/work").join(stage)).unwrap(); } let agents = std::sync::Arc::new(AgentPool::new_test(3000)); let response = handle_assign("Timmy", "999", "opus", tmp.path(), &agents).await; @@ -394,7 +394,7 @@ mod tests { ); let contents = std::fs::read_to_string( - tmp.path().join(".storkit/work/1_backlog/42_story_test.md"), + tmp.path().join(".huskies/work/1_backlog/42_story_test.md"), ) .unwrap(); assert!( @@ -426,7 +426,7 @@ mod tests { ); let contents = std::fs::read_to_string( - tmp.path().join(".storkit/work/1_backlog/7_story_small.md"), + tmp.path().join(".huskies/work/1_backlog/7_story_small.md"), ) .unwrap(); assert!( @@ -449,7 +449,7 @@ mod tests { handle_assign("Timmy", "5", "opus", tmp.path(), &agents).await; let contents = std::fs::read_to_string( - tmp.path().join(".storkit/work/1_backlog/5_story_existing.md"), + tmp.path().join(".huskies/work/1_backlog/5_story_existing.md"), ) .unwrap(); assert!( diff --git a/server/src/chat/transport/matrix/bot/history.rs b/server/src/chat/transport/matrix/bot/history.rs index 958e345f..bddc9970 100644 --- a/server/src/chat/transport/matrix/bot/history.rs +++ b/server/src/chat/transport/matrix/bot/history.rs @@ -51,7 +51,7 @@ pub(super) struct PersistedHistory { } /// Path to the persisted conversation history file relative to project root. -pub(super) const HISTORY_FILE: &str = ".storkit/matrix_history.json"; +pub(super) const HISTORY_FILE: &str = ".huskies/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 { @@ -197,7 +197,7 @@ mod tests { #[test] fn save_and_load_history_round_trip() { let dir = tempfile::tempdir().unwrap(); - let story_kit_dir = dir.path().join(".storkit"); + let story_kit_dir = dir.path().join(".huskies"); std::fs::create_dir_all(&story_kit_dir).unwrap(); let room_id: OwnedRoomId = "!persist:example.com".parse().unwrap(); @@ -238,7 +238,7 @@ mod tests { #[test] fn load_history_returns_empty_on_corrupt_file() { let dir = tempfile::tempdir().unwrap(); - let story_kit_dir = dir.path().join(".storkit"); + let story_kit_dir = dir.path().join(".huskies"); 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()); diff --git a/server/src/chat/transport/matrix/bot/run.rs b/server/src/chat/transport/matrix/bot/run.rs index 11e37b11..a64fe41b 100644 --- a/server/src/chat/transport/matrix/bot/run.rs +++ b/server/src/chat/transport/matrix/bot/run.rs @@ -27,7 +27,7 @@ pub async fn run_bot( agents: Arc, shutdown_rx: watch::Receiver>, ) -> Result<(), String> { - let store_path = project_root.join(".storkit").join("matrix_store"); + let store_path = project_root.join(".huskies").join("matrix_store"); let client = Client::builder() .homeserver_url(config.homeserver.as_deref().unwrap_or_default()) .sqlite_store(&store_path, None) @@ -36,7 +36,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(".storkit").join("matrix_device_id"); + let device_id_path = project_root.join(".huskies").join("matrix_device_id"); let saved_device_id: Option = std::fs::read_to_string(&device_id_path) .ok() .map(|s| s.trim().to_string()) @@ -48,7 +48,7 @@ pub async fn run_bot( config.username.as_deref().unwrap_or_default(), config.password.as_deref().unwrap_or_default(), ) - .initial_device_display_name("Storkit Bot"); + .initial_device_display_name("Huskies Bot"); if let Some(ref device_id) = saved_device_id { login_builder = login_builder.device_id(device_id); @@ -218,7 +218,7 @@ pub async fn run_bot( let announce_bot_name = bot_name.clone(); let timer_store = Arc::new(crate::chat::timer::TimerStore::load( - project_root.join(".storkit").join("timers.json"), + project_root.join(".huskies").join("timers.json"), )); crate::chat::timer::spawn_timer_tick_loop( Arc::clone(&timer_store), diff --git a/server/src/chat/transport/matrix/config.rs b/server/src/chat/transport/matrix/config.rs index 751c20bd..7c4b211f 100644 --- a/server/src/chat/transport/matrix/config.rs +++ b/server/src/chat/transport/matrix/config.rs @@ -9,7 +9,7 @@ fn default_permission_timeout_secs() -> u64 { 120 } -/// Configuration for the Matrix bot, read from `.storkit/bot.toml`. +/// Configuration for the Matrix bot, read from `.huskies/bot.toml`. #[derive(Deserialize, Clone, Debug)] pub struct BotConfig { /// Matrix homeserver URL, e.g. `https://matrix.example.com` @@ -145,12 +145,12 @@ fn default_whatsapp_provider() -> String { } impl BotConfig { - /// Load bot configuration from `.storkit/bot.toml`. + /// Load bot configuration from `.huskies/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 { - let path = project_root.join(".storkit").join("bot.toml"); + let path = project_root.join(".huskies").join("bot.toml"); if !path.exists() { return None; } @@ -285,7 +285,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(".storkit").join("bot.toml"); + let path = project_root.join(".huskies").join("bot.toml"); let content = match std::fs::read_to_string(&path) { Ok(c) => c, Err(e) => { @@ -334,7 +334,7 @@ mod tests { #[test] fn load_returns_none_when_disabled() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); fs::create_dir_all(&sk).unwrap(); fs::write( sk.join("bot.toml"), @@ -354,7 +354,7 @@ enabled = false #[test] fn load_returns_config_when_enabled_with_room_ids() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); fs::create_dir_all(&sk).unwrap(); fs::write( sk.join("bot.toml"), @@ -382,7 +382,7 @@ enabled = true #[test] fn load_merges_deprecated_room_id_into_room_ids() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); fs::create_dir_all(&sk).unwrap(); // Old-style single room_id key — should still work. fs::write( @@ -403,7 +403,7 @@ enabled = true #[test] fn load_returns_none_when_no_room_ids() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); fs::create_dir_all(&sk).unwrap(); fs::write( sk.join("bot.toml"), @@ -422,7 +422,7 @@ enabled = true #[test] fn load_returns_none_when_toml_invalid() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); fs::create_dir_all(&sk).unwrap(); fs::write(sk.join("bot.toml"), "not valid toml {{{").unwrap(); let result = BotConfig::load(tmp.path()); @@ -432,7 +432,7 @@ enabled = true #[test] fn load_respects_optional_model() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); fs::create_dir_all(&sk).unwrap(); fs::write( sk.join("bot.toml"), @@ -453,7 +453,7 @@ model = "claude-sonnet-4-6" #[test] fn load_uses_default_history_size() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); fs::create_dir_all(&sk).unwrap(); fs::write( sk.join("bot.toml"), @@ -473,7 +473,7 @@ enabled = true #[test] fn load_respects_custom_history_size() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); fs::create_dir_all(&sk).unwrap(); fs::write( sk.join("bot.toml"), @@ -494,7 +494,7 @@ history_size = 50 #[test] fn load_reads_display_name() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); fs::create_dir_all(&sk).unwrap(); fs::write( sk.join("bot.toml"), @@ -515,7 +515,7 @@ display_name = "Timmy" #[test] fn load_display_name_defaults_to_none_when_absent() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); fs::create_dir_all(&sk).unwrap(); fs::write( sk.join("bot.toml"), @@ -535,7 +535,7 @@ enabled = true #[test] fn load_uses_default_permission_timeout() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); fs::create_dir_all(&sk).unwrap(); fs::write( sk.join("bot.toml"), @@ -555,7 +555,7 @@ enabled = true #[test] fn load_respects_custom_permission_timeout() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); fs::create_dir_all(&sk).unwrap(); fs::write( sk.join("bot.toml"), @@ -579,7 +579,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(".storkit"); + let sk = tmp.path().join(".huskies"); fs::create_dir_all(&sk).unwrap(); fs::write( sk.join("bot.toml"), @@ -604,7 +604,7 @@ require_verified_devices = true #[test] fn load_reads_ambient_rooms() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); fs::create_dir_all(&sk).unwrap(); fs::write( sk.join("bot.toml"), @@ -625,7 +625,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(".storkit"); + let sk = tmp.path().join(".huskies"); fs::create_dir_all(&sk).unwrap(); fs::write( sk.join("bot.toml"), @@ -645,7 +645,7 @@ enabled = true #[test] fn save_ambient_rooms_persists_to_bot_toml() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); fs::create_dir_all(&sk).unwrap(); fs::write( sk.join("bot.toml"), @@ -667,7 +667,7 @@ enabled = true #[test] fn save_ambient_rooms_clears_when_empty() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); fs::create_dir_all(&sk).unwrap(); fs::write( sk.join("bot.toml"), @@ -690,7 +690,7 @@ ambient_rooms = ["!abc:example.com"] #[test] fn load_transport_defaults_to_matrix() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); fs::create_dir_all(&sk).unwrap(); fs::write( sk.join("bot.toml"), @@ -710,7 +710,7 @@ enabled = true #[test] fn load_transport_reads_custom_value() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); fs::create_dir_all(&sk).unwrap(); fs::write( sk.join("bot.toml"), @@ -746,7 +746,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(".storkit"); + let sk = tmp.path().join(".huskies"); fs::create_dir_all(&sk).unwrap(); fs::write( sk.join("bot.toml"), @@ -767,7 +767,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(".storkit"); + let sk = tmp.path().join(".huskies"); fs::create_dir_all(&sk).unwrap(); fs::write( sk.join("bot.toml"), @@ -788,7 +788,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(".storkit"); + let sk = tmp.path().join(".huskies"); fs::create_dir_all(&sk).unwrap(); fs::write( sk.join("bot.toml"), @@ -811,7 +811,7 @@ whatsapp_access_token = "EAAtoken" #[test] fn load_twilio_whatsapp_reads_config() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); fs::create_dir_all(&sk).unwrap(); fs::write( sk.join("bot.toml"), @@ -842,7 +842,7 @@ twilio_whatsapp_number = "+14155551234" #[test] fn load_whatsapp_provider_defaults_to_meta() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); fs::create_dir_all(&sk).unwrap(); fs::write( sk.join("bot.toml"), @@ -865,7 +865,7 @@ whatsapp_verify_token = "my-verify" #[test] fn load_twilio_returns_none_when_missing_account_sid() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); fs::create_dir_all(&sk).unwrap(); fs::write( sk.join("bot.toml"), @@ -887,7 +887,7 @@ twilio_whatsapp_number = "+14155551234" #[test] fn load_twilio_returns_none_when_missing_auth_token() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); fs::create_dir_all(&sk).unwrap(); fs::write( sk.join("bot.toml"), @@ -909,7 +909,7 @@ twilio_whatsapp_number = "+14155551234" #[test] fn load_twilio_returns_none_when_missing_whatsapp_number() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); fs::create_dir_all(&sk).unwrap(); fs::write( sk.join("bot.toml"), @@ -933,7 +933,7 @@ twilio_auth_token = "authtest" #[test] fn load_slack_transport_reads_config() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); fs::create_dir_all(&sk).unwrap(); fs::write( sk.join("bot.toml"), @@ -959,7 +959,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(".storkit"); + let sk = tmp.path().join(".huskies"); fs::create_dir_all(&sk).unwrap(); fs::write( sk.join("bot.toml"), @@ -980,7 +980,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(".storkit"); + let sk = tmp.path().join(".huskies"); fs::create_dir_all(&sk).unwrap(); fs::write( sk.join("bot.toml"), @@ -1001,7 +1001,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(".storkit"); + let sk = tmp.path().join(".huskies"); fs::create_dir_all(&sk).unwrap(); fs::write( sk.join("bot.toml"), diff --git a/server/src/chat/transport/matrix/delete.rs b/server/src/chat/transport/matrix/delete.rs index 906549ff..981407b5 100644 --- a/server/src/chat/transport/matrix/delete.rs +++ b/server/src/chat/transport/matrix/delete.rs @@ -72,7 +72,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(".storkit").join("work").join(stage); + let dir = project_root.join(".huskies").join("work").join(stage); if !dir.exists() { continue; } @@ -148,8 +148,8 @@ pub async fn handle_delete( } // Commit the deletion to git. - let commit_msg = format!("storkit: delete {story_id}"); - let work_rel = std::path::PathBuf::from(".storkit").join("work"); + let commit_msg = format!("huskies: delete {story_id}"); + let work_rel = std::path::PathBuf::from(".huskies").join("work"); let _ = std::process::Command::new("git") .args(["add", "-A"]) .arg(&work_rel) @@ -288,7 +288,7 @@ mod tests { "5_done", "6_archived", ] { - std::fs::create_dir_all(project_root.join(".storkit").join("work").join(stage)) + std::fs::create_dir_all(project_root.join(".huskies").join("work").join(stage)) .unwrap(); } let agents = std::sync::Arc::new(crate::agents::AgentPool::new_test(3000)); @@ -321,7 +321,7 @@ mod tests { .output() .unwrap(); - let backlog_dir = project_root.join(".storkit").join("work").join("1_backlog"); + let backlog_dir = project_root.join(".huskies").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(&story_path, "---\nname: Some Feature\n---\n\n# Story 42\n").unwrap(); diff --git a/server/src/chat/transport/matrix/mod.rs b/server/src/chat/transport/matrix/mod.rs index 4d2e6da5..7aeece38 100644 --- a/server/src/chat/transport/matrix/mod.rs +++ b/server/src/chat/transport/matrix/mod.rs @@ -1,6 +1,6 @@ //! Matrix bot integration for Story Kit. //! -//! When a `.storkit/bot.toml` file is present with `enabled = true`, the +//! When a `.huskies/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. @@ -41,7 +41,7 @@ use tokio::sync::{Mutex as TokioMutex, broadcast, mpsc, watch}; /// Attempt to start the Matrix bot. /// -/// Reads the bot configuration from `.storkit/bot.toml`. If the file is +/// Reads the bot configuration from `.huskies/bot.toml`. If the file is /// absent or `enabled = false`, this function returns immediately without /// spawning anything — the server continues normally. /// diff --git a/server/src/chat/transport/matrix/notifications.rs b/server/src/chat/transport/matrix/notifications.rs index 85e20dbb..a6f640f3 100644 --- a/server/src/chat/transport/matrix/notifications.rs +++ b/server/src/chat/transport/matrix/notifications.rs @@ -55,7 +55,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 { let path = project_root - .join(".storkit") + .join(".huskies") .join("work") .join(stage) .join(format!("{item_id}.md")); @@ -507,7 +507,7 @@ mod tests { #[tokio::test] async fn rate_limit_warning_sends_notification_with_agent_and_story() { let tmp = tempfile::tempdir().unwrap(); - let stage_dir = tmp.path().join(".storkit").join("work").join("2_current"); + let stage_dir = tmp.path().join(".huskies").join("work").join("2_current"); std::fs::create_dir_all(&stage_dir).unwrap(); std::fs::write( stage_dir.join("365_story_rate_limit.md"), @@ -613,7 +613,7 @@ mod tests { #[tokio::test] async fn stage_notification_uses_dynamic_room_ids() { let tmp = tempfile::tempdir().unwrap(); - let stage_dir = tmp.path().join(".storkit").join("work").join("3_qa"); + let stage_dir = tmp.path().join(".huskies").join("work").join("3_qa"); std::fs::create_dir_all(&stage_dir).unwrap(); std::fs::write( stage_dir.join("10_story_foo.md"), @@ -642,7 +642,7 @@ mod tests { stage: "3_qa".to_string(), item_id: "10_story_foo".to_string(), action: "qa".to_string(), - commit_msg: "storkit: qa 10_story_foo".to_string(), + commit_msg: "huskies: qa 10_story_foo".to_string(), from_stage: None, }).unwrap(); @@ -677,7 +677,7 @@ mod tests { stage: "3_qa".to_string(), item_id: "10_story_foo".to_string(), action: "qa".to_string(), - commit_msg: "storkit: qa 10_story_foo".to_string(), + commit_msg: "huskies: qa 10_story_foo".to_string(), from_stage: None, }).unwrap(); @@ -746,7 +746,7 @@ mod tests { let tmp = tempfile::tempdir().unwrap(); let stage_dir = tmp .path() - .join(".storkit") + .join(".huskies") .join("work") .join("2_current"); std::fs::create_dir_all(&stage_dir).unwrap(); @@ -772,7 +772,7 @@ mod tests { let tmp = tempfile::tempdir().unwrap(); let stage_dir = tmp .path() - .join(".storkit") + .join(".huskies") .join("work") .join("2_current"); std::fs::create_dir_all(&stage_dir).unwrap(); @@ -858,7 +858,7 @@ mod tests { #[tokio::test] async fn story_blocked_sends_notification_with_reason() { let tmp = tempfile::tempdir().unwrap(); - let stage_dir = tmp.path().join(".storkit").join("work").join("2_current"); + let stage_dir = tmp.path().join(".huskies").join("work").join("2_current"); std::fs::create_dir_all(&stage_dir).unwrap(); std::fs::write( stage_dir.join("425_story_blocking_test.md"), @@ -1033,7 +1033,7 @@ mod tests { #[tokio::test] async fn rate_limit_warning_suppressed_when_config_false() { let tmp = tempfile::tempdir().unwrap(); - let sk_dir = tmp.path().join(".storkit"); + let sk_dir = tmp.path().join(".huskies"); std::fs::create_dir_all(&sk_dir).unwrap(); std::fs::write( sk_dir.join("project.toml"), @@ -1066,7 +1066,7 @@ mod tests { #[tokio::test] async fn rate_limit_hard_block_always_sent_when_config_false() { let tmp = tempfile::tempdir().unwrap(); - let sk_dir = tmp.path().join(".storkit"); + let sk_dir = tmp.path().join(".huskies"); std::fs::create_dir_all(&sk_dir).unwrap(); std::fs::write( sk_dir.join("project.toml"), @@ -1101,7 +1101,7 @@ mod tests { #[tokio::test] async fn story_blocked_always_sent_when_config_false() { let tmp = tempfile::tempdir().unwrap(); - let sk_dir = tmp.path().join(".storkit"); + let sk_dir = tmp.path().join(".huskies"); std::fs::create_dir_all(&sk_dir).unwrap(); std::fs::write( sk_dir.join("project.toml"), @@ -1135,7 +1135,7 @@ mod tests { #[tokio::test] async fn rate_limit_warning_suppressed_after_hot_reload() { let tmp = tempfile::tempdir().unwrap(); - let sk_dir = tmp.path().join(".storkit"); + let sk_dir = tmp.path().join(".huskies"); std::fs::create_dir_all(&sk_dir).unwrap(); // Start with notifications enabled. std::fs::write( diff --git a/server/src/chat/transport/matrix/rmtree.rs b/server/src/chat/transport/matrix/rmtree.rs index 5096676f..9d870eb3 100644 --- a/server/src/chat/transport/matrix/rmtree.rs +++ b/server/src/chat/transport/matrix/rmtree.rs @@ -51,7 +51,7 @@ pub fn extract_rmtree_command( /// Handle an rmtree command asynchronously. /// -/// Finds the worktree for `story_number` under `.storkit/worktrees/`, stops any +/// Finds the worktree for `story_number` under `.huskies/worktrees/`, stops any /// running agent, and removes the worktree directory and its feature branch. /// Returns a markdown-formatted response string. pub async fn handle_rmtree( @@ -201,7 +201,7 @@ mod tests { async fn handle_rmtree_returns_not_found_for_unknown_number() { let tmp = tempfile::tempdir().unwrap(); let project_root = tmp.path(); - std::fs::create_dir_all(project_root.join(".storkit").join("worktrees")).unwrap(); + std::fs::create_dir_all(project_root.join(".huskies").join("worktrees")).unwrap(); let agents = std::sync::Arc::new(crate::agents::AgentPool::new_test(3000)); let response = handle_rmtree("Timmy", "999", project_root, &agents).await; assert!( diff --git a/server/src/chat/transport/matrix/start.rs b/server/src/chat/transport/matrix/start.rs index d60f3176..f6e2550f 100644 --- a/server/src/chat/transport/matrix/start.rs +++ b/server/src/chat/transport/matrix/start.rs @@ -91,7 +91,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(".storkit").join("work").join(stage); + let dir = project_root.join(".huskies").join("work").join(stage); if !dir.exists() { continue; } @@ -274,7 +274,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(".storkit").join("work").join(stage)) + std::fs::create_dir_all(project_root.join(".huskies").join("work").join(stage)) .unwrap(); } let agents = std::sync::Arc::new(crate::agents::AgentPool::new_test(3000)); @@ -292,7 +292,7 @@ mod tests { let tmp = tempfile::tempdir().unwrap(); let project_root = tmp.path(); - let sk = project_root.join(".storkit"); + let sk = project_root.join(".huskies"); let backlog = sk.join("work/1_backlog"); std::fs::create_dir_all(&backlog).unwrap(); std::fs::write( diff --git a/server/src/chat/transport/slack/commands.rs b/server/src/chat/transport/slack/commands.rs index 33a0ef8f..9e8a63f9 100644 --- a/server/src/chat/transport/slack/commands.rs +++ b/server/src/chat/transport/slack/commands.rs @@ -22,9 +22,9 @@ use super::format::markdown_to_slack; /// Payload sent by Slack for slash commands (application/x-www-form-urlencoded). #[derive(Deserialize, Debug)] pub struct SlackSlashCommandPayload { - /// The slash command that was invoked (e.g. "/storkit-status"). + /// The slash command that was invoked (e.g. "/huskies-status"). pub command: String, - /// Any text typed after the command (e.g. "42" for "/storkit-show 42"). + /// Any text typed after the command (e.g. "42" for "/huskies-show 42"). #[serde(default)] pub text: String, /// The user who invoked the command. @@ -44,12 +44,12 @@ pub(super) struct SlashCommandResponse { /// Map a Slack slash command name to the corresponding bot command keyword. /// -/// Supported: `/storkit-status`, `/storkit-cost`, `/storkit-show`, -/// `/storkit-git`, `/storkit-htop`. +/// Supported: `/huskies-status`, `/huskies-cost`, `/huskies-show`, +/// `/huskies-git`, `/huskies-htop`. pub(super) fn slash_command_to_bot_keyword(command: &str) -> Option<&'static str> { - // Strip leading "/" and the "storkit-" prefix. + // Strip leading "/" and the "huskies-" prefix. let name = command.strip_prefix('/').unwrap_or(command); - let keyword = name.strip_prefix("storkit-")?; + let keyword = name.strip_prefix("huskies-")?; match keyword { "status" => Some("status"), "cost" => Some("cost"), @@ -539,9 +539,9 @@ mod tests { #[test] fn parse_slash_command_payload() { - let body = "command=%2Fstorkit-status&text=&user_id=U123&channel_id=C456"; + let body = "command=%2Fhuskies-status&text=&user_id=U123&channel_id=C456"; let payload: SlackSlashCommandPayload = serde_urlencoded::from_str(body).unwrap(); - assert_eq!(payload.command, "/storkit-status"); + assert_eq!(payload.command, "/huskies-status"); assert_eq!(payload.text, ""); assert_eq!(payload.user_id, "U123"); assert_eq!(payload.channel_id, "C456"); @@ -549,9 +549,9 @@ mod tests { #[test] fn parse_slash_command_payload_with_text() { - let body = "command=%2Fstorkit-show&text=42&user_id=U123&channel_id=C456"; + let body = "command=%2Fhuskies-show&text=42&user_id=U123&channel_id=C456"; let payload: SlackSlashCommandPayload = serde_urlencoded::from_str(body).unwrap(); - assert_eq!(payload.command, "/storkit-show"); + assert_eq!(payload.command, "/huskies-show"); assert_eq!(payload.text, "42"); } @@ -559,36 +559,36 @@ mod tests { #[test] fn slash_command_maps_status() { - assert_eq!(slash_command_to_bot_keyword("/storkit-status"), Some("status")); + assert_eq!(slash_command_to_bot_keyword("/huskies-status"), Some("status")); } #[test] fn slash_command_maps_cost() { - assert_eq!(slash_command_to_bot_keyword("/storkit-cost"), Some("cost")); + assert_eq!(slash_command_to_bot_keyword("/huskies-cost"), Some("cost")); } #[test] fn slash_command_maps_show() { - assert_eq!(slash_command_to_bot_keyword("/storkit-show"), Some("show")); + assert_eq!(slash_command_to_bot_keyword("/huskies-show"), Some("show")); } #[test] fn slash_command_maps_git() { - assert_eq!(slash_command_to_bot_keyword("/storkit-git"), Some("git")); + assert_eq!(slash_command_to_bot_keyword("/huskies-git"), Some("git")); } #[test] fn slash_command_maps_htop() { - assert_eq!(slash_command_to_bot_keyword("/storkit-htop"), Some("htop")); + assert_eq!(slash_command_to_bot_keyword("/huskies-htop"), Some("htop")); } #[test] fn slash_command_unknown_returns_none() { - assert_eq!(slash_command_to_bot_keyword("/storkit-unknown"), None); + assert_eq!(slash_command_to_bot_keyword("/huskies-unknown"), None); } #[test] - fn slash_command_non_storkit_returns_none() { + fn slash_command_non_huskies_returns_none() { assert_eq!(slash_command_to_bot_keyword("/other-command"), None); } @@ -628,8 +628,8 @@ mod tests { let room_id = "C01ABCDEF".to_string(); // Simulate what slash_command_receive does: build a synthetic message. - let bot_name = "Storkit"; - let keyword = slash_command_to_bot_keyword("/storkit-status").unwrap(); + let bot_name = "Huskies"; + let keyword = slash_command_to_bot_keyword("/huskies-status").unwrap(); let synthetic = format!("{bot_name} {keyword}"); let dispatch = CommandDispatch { @@ -654,9 +654,9 @@ mod tests { let ambient_rooms = test_ambient_rooms(); let room_id = "C01ABCDEF".to_string(); - let bot_name = "Storkit"; - let keyword = slash_command_to_bot_keyword("/storkit-show").unwrap(); - // Simulate /storkit-show with text "999" + let bot_name = "Huskies"; + let keyword = slash_command_to_bot_keyword("/huskies-show").unwrap(); + // Simulate /huskies-show with text "999" let synthetic = format!("{bot_name} {keyword} 999"); let dispatch = CommandDispatch { @@ -679,11 +679,11 @@ mod tests { #[test] fn rebuild_command_extracted_from_slack_message() { let result = crate::chat::transport::matrix::rebuild::extract_rebuild_command( - "Storkit rebuild", - "Storkit", + "Huskies rebuild", + "Huskies", "slack-bot", ); - assert!(result.is_some(), "'Storkit rebuild' should be recognised"); + assert!(result.is_some(), "'Huskies rebuild' should be recognised"); } #[test] @@ -691,7 +691,7 @@ mod tests { // Slack slash-command synthetic messages may not include a bot mention. let result = crate::chat::transport::matrix::rebuild::extract_rebuild_command( "rebuild", - "Storkit", + "Huskies", "slack-bot", ); assert!(result.is_some(), "plain 'rebuild' should be recognised"); @@ -700,8 +700,8 @@ mod tests { #[test] fn non_rebuild_slack_message_not_extracted() { let result = crate::chat::transport::matrix::rebuild::extract_rebuild_command( - "Storkit status", - "Storkit", + "Huskies status", + "Huskies", "slack-bot", ); assert!(result.is_none(), "'status' should not be recognised as rebuild"); @@ -712,18 +712,18 @@ mod tests { #[test] fn reset_command_extracted_from_slack_message() { let result = crate::chat::transport::matrix::reset::extract_reset_command( - "Storkit reset", - "Storkit", + "Huskies reset", + "Huskies", "slack-bot", ); - assert!(result.is_some(), "'Storkit reset' should be recognised"); + assert!(result.is_some(), "'Huskies reset' should be recognised"); } #[test] fn reset_command_extracted_plain_no_mention() { let result = crate::chat::transport::matrix::reset::extract_reset_command( "reset", - "Storkit", + "Huskies", "slack-bot", ); assert!(result.is_some(), "plain 'reset' should be recognised"); @@ -750,7 +750,7 @@ mod tests { })); let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); std::fs::create_dir_all(&sk).unwrap(); { diff --git a/server/src/chat/transport/slack/history.rs b/server/src/chat/transport/slack/history.rs index f77f8eb7..c4a1f3df 100644 --- a/server/src/chat/transport/slack/history.rs +++ b/server/src/chat/transport/slack/history.rs @@ -18,7 +18,7 @@ struct PersistedSlackHistory { } /// Path to the persisted Slack conversation history file. -const SLACK_HISTORY_FILE: &str = ".storkit/slack_history.json"; +const SLACK_HISTORY_FILE: &str = ".huskies/slack_history.json"; /// Load Slack conversation history from disk. pub fn load_slack_history(project_root: &std::path::Path) -> HashMap { @@ -66,7 +66,7 @@ mod tests { #[test] fn save_and_load_slack_history_round_trips() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); std::fs::create_dir_all(&sk).unwrap(); let mut history = HashMap::new(); @@ -110,7 +110,7 @@ mod tests { #[test] fn load_slack_history_returns_empty_on_invalid_json() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); std::fs::create_dir_all(&sk).unwrap(); std::fs::write(sk.join("slack_history.json"), "not json {{{").unwrap(); let history = load_slack_history(tmp.path()); diff --git a/server/src/chat/transport/whatsapp/commands.rs b/server/src/chat/transport/whatsapp/commands.rs index d410b418..adffd97a 100644 --- a/server/src/chat/transport/whatsapp/commands.rs +++ b/server/src/chat/transport/whatsapp/commands.rs @@ -635,7 +635,7 @@ mod tests { })); let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); std::fs::create_dir_all(&sk).unwrap(); { diff --git a/server/src/chat/transport/whatsapp/history.rs b/server/src/chat/transport/whatsapp/history.rs index b8027c9a..8035c3c2 100644 --- a/server/src/chat/transport/whatsapp/history.rs +++ b/server/src/chat/transport/whatsapp/history.rs @@ -79,7 +79,7 @@ struct PersistedWhatsAppHistory { } /// Path to the persisted WhatsApp conversation history file. -const WHATSAPP_HISTORY_FILE: &str = ".storkit/whatsapp_history.json"; +const WHATSAPP_HISTORY_FILE: &str = ".huskies/whatsapp_history.json"; /// Load WhatsApp conversation history from disk. pub fn load_whatsapp_history(project_root: &std::path::Path) -> HashMap { @@ -162,7 +162,7 @@ mod tests { #[test] fn save_and_load_whatsapp_history_round_trips() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); std::fs::create_dir_all(&sk).unwrap(); let mut history = HashMap::new(); @@ -206,7 +206,7 @@ mod tests { #[test] fn load_whatsapp_history_returns_empty_on_invalid_json() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); std::fs::create_dir_all(&sk).unwrap(); std::fs::write(sk.join("whatsapp_history.json"), "not json {{{").unwrap(); let history = load_whatsapp_history(tmp.path()); @@ -216,7 +216,7 @@ mod tests { #[test] fn save_whatsapp_history_preserves_multiple_senders() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); std::fs::create_dir_all(&sk).unwrap(); let mut history = HashMap::new(); diff --git a/server/src/chat/util.rs b/server/src/chat/util.rs index 1f9dff5b..3e563114 100644 --- a/server/src/chat/util.rs +++ b/server/src/chat/util.rs @@ -63,11 +63,11 @@ pub fn strip_bot_mention<'a>(message: &'a str, bot_name: &str, bot_user_id: &str if let Some(close_paren) = url_content.find(')') { let url = &url_content[..close_paren]; // "https://matrix.to/#/@user:server" let matrix_prefix = "https://matrix.to/#/"; - if let Some(mentioned_id) = url.strip_prefix(matrix_prefix) { - if mentioned_id.eq_ignore_ascii_case(bot_user_id) { - let rest = &url_content[close_paren + 1..]; - return strip_mention_separator(rest); - } + if let Some(mentioned_id) = url.strip_prefix(matrix_prefix) + && mentioned_id.eq_ignore_ascii_case(bot_user_id) + { + let rest = &url_content[close_paren + 1..]; + return strip_mention_separator(rest); } } } diff --git a/server/src/config.rs b/server/src/config.rs index 896546a2..f0795a86 100644 --- a/server/src/config.rs +++ b/server/src/config.rs @@ -163,7 +163,7 @@ fn default_agent_command() -> String { fn default_agent_prompt() -> String { "You are working in a git worktree on story {{story_id}}. \ - Read .storkit/README.md to understand the dev process, then pick up the story. \ + Read .huskies/README.md to understand the dev process, then pick up the story. \ Commit all your work when done — the server will automatically run acceptance \ gates (cargo clippy + tests) when your process exits." .to_string() @@ -225,13 +225,13 @@ impl Default for ProjectConfig { } impl ProjectConfig { - /// Load from `.storkit/project.toml` relative to the given root. + /// Load from `.huskies/project.toml` relative to the given root. /// Falls back to sensible defaults if the file doesn't exist. /// /// Supports both the new `[[agent]]` array format and the legacy /// `[agent]` single-table format (with a deprecation warning). pub fn load(project_root: &Path) -> Result { - let config_path = project_root.join(".storkit/project.toml"); + let config_path = project_root.join(".huskies/project.toml"); if !config_path.exists() { return Ok(Self::default()); } @@ -640,7 +640,7 @@ name = "second" #[test] fn parse_project_toml_from_file() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); fs::create_dir_all(&sk).unwrap(); fs::write( sk.join("project.toml"), @@ -721,7 +721,7 @@ name = "coder" #[test] fn watcher_config_from_file() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); fs::create_dir_all(&sk).unwrap(); fs::write( sk.join("project.toml"), diff --git a/server/src/http/agents.rs b/server/src/http/agents.rs index 96c9d0a2..0cc58bd5 100644 --- a/server/src/http/agents.rs +++ b/server/src/http/agents.rs @@ -158,7 +158,7 @@ struct AllTokenUsageResponse { /// response so the agents panel is not cluttered with old completed items on /// frontend startup. pub fn story_is_archived(project_root: &path::Path, story_id: &str) -> bool { - let work = project_root.join(".storkit").join("work"); + let work = project_root.join(".huskies").join("work"); let filename = format!("{story_id}.md"); work.join("5_done").join(&filename).exists() || work.join("6_archived").join(&filename).exists() } @@ -307,7 +307,7 @@ impl AgentsApi { )) } - /// Create a git worktree for a story under .storkit/worktrees/{story_id}. + /// Create a git worktree for a story under .huskies/worktrees/{story_id}. #[oai(path = "/agents/worktrees", method = "post")] async fn create_worktree( &self, @@ -334,7 +334,7 @@ impl AgentsApi { })) } - /// List all worktrees under .storkit/worktrees/. + /// List all worktrees under .huskies/worktrees/. #[oai(path = "/agents/worktrees", method = "get")] async fn list_worktrees(&self) -> OpenApiResult>> { let project_root = self @@ -380,7 +380,7 @@ impl AgentsApi { ("6_archived", "archived"), ]; - let work_dir = project_root.join(".storkit").join("work"); + let work_dir = project_root.join(".huskies").join("work"); let filename = format!("{}.md", story_id.0); for (stage_dir, stage_name) in &stages { @@ -593,7 +593,7 @@ mod tests { fn make_work_dirs(tmp: &TempDir) -> path::PathBuf { let root = tmp.path().to_path_buf(); for stage in &["5_done", "6_archived"] { - std::fs::create_dir_all(root.join(".storkit").join("work").join(stage)).unwrap(); + std::fs::create_dir_all(root.join(".huskies").join("work").join(stage)).unwrap(); } root } @@ -610,7 +610,7 @@ mod tests { let tmp = TempDir::new().unwrap(); let root = make_work_dirs(&tmp); std::fs::write( - root.join(".storkit/work/5_done/79_story_foo.md"), + root.join(".huskies/work/5_done/79_story_foo.md"), "---\nname: test\n---\n", ) .unwrap(); @@ -622,7 +622,7 @@ mod tests { let tmp = TempDir::new().unwrap(); let root = make_work_dirs(&tmp); std::fs::write( - root.join(".storkit/work/6_archived/79_story_foo.md"), + root.join(".huskies/work/6_archived/79_story_foo.md"), "---\nname: test\n---\n", ) .unwrap(); @@ -636,7 +636,7 @@ mod tests { // Place an archived story file in 6_archived std::fs::write( - root.join(".storkit/work/6_archived/79_story_archived.md"), + root.join(".huskies/work/6_archived/79_story_archived.md"), "---\nname: archived story\n---\n", ) .unwrap(); @@ -679,7 +679,7 @@ mod tests { } fn make_project_toml(root: &path::Path, content: &str) { - let sk_dir = root.join(".storkit"); + let sk_dir = root.join(".huskies"); std::fs::create_dir_all(&sk_dir).unwrap(); std::fs::write(sk_dir.join("project.toml"), content).unwrap(); } @@ -801,7 +801,7 @@ allowed_tools = ["Read", "Bash"] #[tokio::test] async fn list_worktrees_returns_entries_from_dir() { let tmp = TempDir::new().unwrap(); - let worktrees_dir = tmp.path().join(".storkit").join("worktrees"); + let worktrees_dir = tmp.path().join(".huskies").join("worktrees"); std::fs::create_dir_all(worktrees_dir.join("42_story_foo")).unwrap(); std::fs::create_dir_all(worktrees_dir.join("43_story_bar")).unwrap(); @@ -894,7 +894,7 @@ allowed_tools = ["Read", "Bash"] // --- get_work_item_content tests --- fn make_stage_dir(root: &path::Path, stage: &str) { - std::fs::create_dir_all(root.join(".storkit").join("work").join(stage)).unwrap(); + std::fs::create_dir_all(root.join(".huskies").join("work").join(stage)).unwrap(); } #[tokio::test] @@ -903,7 +903,7 @@ allowed_tools = ["Read", "Bash"] let root = tmp.path(); make_stage_dir(root, "1_backlog"); std::fs::write( - root.join(".storkit/work/1_backlog/42_story_foo.md"), + root.join(".huskies/work/1_backlog/42_story_foo.md"), "---\nname: \"Foo Story\"\n---\n\n# Story 42: Foo Story\n\nSome content.", ) .unwrap(); @@ -925,7 +925,7 @@ allowed_tools = ["Read", "Bash"] let root = tmp.path(); make_stage_dir(root, "2_current"); std::fs::write( - root.join(".storkit/work/2_current/43_story_bar.md"), + root.join(".huskies/work/2_current/43_story_bar.md"), "---\nname: \"Bar Story\"\n---\n\nBar content.", ) .unwrap(); @@ -1174,7 +1174,7 @@ allowed_tools = ["Read", "Bash"] let root = tmp.path().to_path_buf(); // Create work dirs including 2_current for the story file. for stage in &["1_backlog", "2_current", "5_done", "6_archived"] { - std::fs::create_dir_all(root.join(".storkit").join("work").join(stage)).unwrap(); + std::fs::create_dir_all(root.join(".huskies").join("work").join(stage)).unwrap(); } // Write a story file with persisted test results. @@ -1185,10 +1185,10 @@ name: "Test story" ## Test Results - + "#; std::fs::write( - root.join(".storkit/work/2_current/42_story_foo.md"), + root.join(".huskies/work/2_current/42_story_foo.md"), story_content, ) .unwrap(); diff --git a/server/src/http/context.rs b/server/src/http/context.rs index 08f796f7..d9a41e49 100644 --- a/server/src/http/context.rs +++ b/server/src/http/context.rs @@ -74,7 +74,7 @@ impl AppContext { pub fn new_test(project_root: std::path::PathBuf) -> Self { let state = SessionState::default(); *state.project_root.lock().unwrap() = Some(project_root.clone()); - let store_path = project_root.join(".storkit_store.json"); + let store_path = project_root.join(".huskies_store.json"); let (watcher_tx, _) = broadcast::channel(64); let (reconciliation_tx, _) = broadcast::channel(64); let (perm_tx, perm_rx) = mpsc::unbounded_channel(); diff --git a/server/src/http/mcp/agent_tools.rs b/server/src/http/mcp/agent_tools.rs index 85c162f3..52390fd8 100644 --- a/server/src/http/mcp/agent_tools.rs +++ b/server/src/http/mcp/agent_tools.rs @@ -42,11 +42,11 @@ pub(super) async fn tool_start_agent(args: &Value, ctx: &AppContext) -> Result Option { let path = project_root - .join(".storkit") + .join(".huskies") .join("coverage") .join("server.json"); let contents = std::fs::read_to_string(&path).ok()?; @@ -485,7 +485,7 @@ mod tests { // Config has only a supervisor — start_agent without agent_name should // refuse rather than silently assigning supervisor. let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); std::fs::create_dir_all(&sk).unwrap(); std::fs::write( sk.join("project.toml"), @@ -513,7 +513,7 @@ stage = "other" // missing git repo / worktree, but the error must NOT be about // "No coder agent configured". let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); std::fs::create_dir_all(&sk).unwrap(); std::fs::write( sk.join("project.toml"), @@ -709,7 +709,7 @@ stage = "coder" fn read_coverage_percent_from_json_parses_llvm_cov_format() { use std::fs; let tmp = tempfile::tempdir().unwrap(); - let cov_dir = tmp.path().join(".storkit/coverage"); + let cov_dir = tmp.path().join(".huskies/coverage"); fs::create_dir_all(&cov_dir).unwrap(); let json_content = r#"{"data":[{"totals":{"lines":{"count":100,"covered":78,"percent":78.0}}}]}"#; fs::write(cov_dir.join("server.json"), json_content).unwrap(); diff --git a/server/src/http/mcp/diagnostics.rs b/server/src/http/mcp/diagnostics.rs index 3cdca08d..ad962a65 100644 --- a/server/src/http/mcp/diagnostics.rs +++ b/server/src/http/mcp/diagnostics.rs @@ -47,7 +47,7 @@ pub(super) async fn tool_rebuild_and_restart(ctx: &AppContext) -> Result String { if tool_name == "Bash" { // Extract command from tool_input.command and use first word as prefix @@ -109,8 +109,8 @@ pub(super) fn add_permission_rule( return Ok(()); } - // Also check for wildcard coverage: if "mcp__storkit__*" exists, don't add - // a more specific "mcp__storkit__create_story". + // Also check for wildcard coverage: if "mcp__huskies__*" exists, don't add + // a more specific "mcp__huskies__create_story". let dominated = allow.iter().any(|existing| { if let Some(pat) = existing.as_str() && let Some(prefix) = pat.strip_suffix('*') @@ -470,8 +470,8 @@ mod tests { #[test] fn generate_rule_for_mcp_tool() { - let rule = generate_permission_rule("mcp__storkit__create_story", &json!({"name": "foo"})); - assert_eq!(rule, "mcp__storkit__create_story"); + let rule = generate_permission_rule("mcp__huskies__create_story", &json!({"name": "foo"})); + assert_eq!(rule, "mcp__huskies__create_story"); } // ── Settings.json writing tests ────────────────────────────── @@ -507,17 +507,17 @@ mod tests { fs::create_dir_all(&claude_dir).unwrap(); fs::write( claude_dir.join("settings.json"), - r#"{"permissions":{"allow":["mcp__storkit__*"]}}"#, + r#"{"permissions":{"allow":["mcp__huskies__*"]}}"#, ) .unwrap(); - add_permission_rule(tmp.path(), "mcp__storkit__create_story").unwrap(); + add_permission_rule(tmp.path(), "mcp__huskies__create_story").unwrap(); let content = fs::read_to_string(claude_dir.join("settings.json")).unwrap(); let settings: Value = serde_json::from_str(&content).unwrap(); let allow = settings["permissions"]["allow"].as_array().unwrap(); assert_eq!(allow.len(), 1); - assert_eq!(allow[0], "mcp__storkit__*"); + assert_eq!(allow[0], "mcp__huskies__*"); } #[test] @@ -548,7 +548,7 @@ mod tests { fs::create_dir_all(&claude_dir).unwrap(); fs::write( claude_dir.join("settings.json"), - r#"{"permissions":{"allow":["Edit"]},"enabledMcpjsonServers":["storkit"]}"#, + r#"{"permissions":{"allow":["Edit"]},"enabledMcpjsonServers":["huskies"]}"#, ) .unwrap(); @@ -558,7 +558,7 @@ mod tests { let settings: Value = serde_json::from_str(&content).unwrap(); let servers = settings["enabledMcpjsonServers"].as_array().unwrap(); assert_eq!(servers.len(), 1); - assert_eq!(servers[0], "storkit"); + assert_eq!(servers[0], "huskies"); } #[test] @@ -598,9 +598,9 @@ mod tests { // binary, otherwise cargo build outputs to a different target dir and // current_exe() still points at the old binary. let build_args: Vec<&str> = if cfg!(debug_assertions) { - vec!["build", "-p", "storkit"] + vec!["build", "-p", "huskies"] } else { - vec!["build", "--release", "-p", "storkit"] + vec!["build", "--release", "-p", "huskies"] }; // Tests always run in debug mode, so --release must NOT be present. @@ -652,7 +652,7 @@ mod tests { let tmp = tempfile::tempdir().unwrap(); let root = tmp.path(); // Seed project root in state so get_project_root works - let backlog = root.join(".storkit/work/1_backlog"); + let backlog = root.join(".huskies/work/1_backlog"); fs::create_dir_all(&backlog).unwrap(); fs::write(backlog.join("1_story_test.md"), "---\nname: Test\n---\n").unwrap(); let ctx = test_ctx(root); @@ -668,8 +668,8 @@ mod tests { fn tool_move_story_moves_from_backlog_to_current() { let tmp = tempfile::tempdir().unwrap(); let root = tmp.path(); - let backlog = root.join(".storkit/work/1_backlog"); - let current = root.join(".storkit/work/2_current"); + let backlog = root.join(".huskies/work/1_backlog"); + let current = root.join(".huskies/work/2_current"); fs::create_dir_all(&backlog).unwrap(); fs::create_dir_all(¤t).unwrap(); fs::write(backlog.join("5_story_test.md"), "---\nname: Test\n---\n").unwrap(); @@ -693,8 +693,8 @@ mod tests { fn tool_move_story_moves_from_current_to_backlog() { let tmp = tempfile::tempdir().unwrap(); let root = tmp.path(); - let current = root.join(".storkit/work/2_current"); - let backlog = root.join(".storkit/work/1_backlog"); + let current = root.join(".huskies/work/2_current"); + let backlog = root.join(".huskies/work/1_backlog"); fs::create_dir_all(¤t).unwrap(); fs::create_dir_all(&backlog).unwrap(); fs::write(current.join("6_story_back.md"), "---\nname: Back\n---\n").unwrap(); @@ -717,7 +717,7 @@ mod tests { fn tool_move_story_idempotent_when_already_in_target() { let tmp = tempfile::tempdir().unwrap(); let root = tmp.path(); - let current = root.join(".storkit/work/2_current"); + let current = root.join(".huskies/work/2_current"); fs::create_dir_all(¤t).unwrap(); fs::write(current.join("7_story_idem.md"), "---\nname: Idem\n---\n").unwrap(); diff --git a/server/src/http/mcp/git_tools.rs b/server/src/http/mcp/git_tools.rs index 387c50c9..0111c70d 100644 --- a/server/src/http/mcp/git_tools.rs +++ b/server/src/http/mcp/git_tools.rs @@ -3,7 +3,7 @@ use serde_json::{json, Value}; use std::path::PathBuf; /// Validates that `worktree_path` exists and is inside the project's -/// `.storkit/worktrees/` directory. Returns the canonicalized path. +/// `.huskies/worktrees/` directory. Returns the canonicalized path. fn validate_worktree_path(worktree_path: &str, ctx: &AppContext) -> Result { let wd = PathBuf::from(worktree_path); @@ -17,7 +17,7 @@ fn validate_worktree_path(worktree_path: &str, ctx: &AppContext) -> Result Result Resul // survives server restarts and is visible in the web UI. if let Ok(project_root) = ctx.state.get_project_root() { let story_file = project_root - .join(".storkit") + .join(".huskies") .join("work") .join("4_merge") .join(format!("{story_id}.md")); @@ -243,7 +243,7 @@ mod tests { async fn tool_move_story_to_merge_moves_file() { let tmp = tempfile::tempdir().unwrap(); setup_git_repo_in(tmp.path()); - let current_dir = tmp.path().join(".storkit/work/2_current"); + let current_dir = tmp.path().join(".huskies/work/2_current"); std::fs::create_dir_all(¤t_dir).unwrap(); let story_file = current_dir.join("24_story_test.md"); std::fs::write(&story_file, "---\nname: Test\n---\n").unwrap(); @@ -264,7 +264,7 @@ mod tests { // File should have been moved regardless of agent start outcome assert!(!story_file.exists(), "2_current file should be gone"); assert!( - tmp.path().join(".storkit/work/4_merge/24_story_test.md").exists(), + tmp.path().join(".huskies/work/4_merge/24_story_test.md").exists(), "4_merge file should exist" ); // Result is either Ok (agent started) or Err (agent failed - acceptable in tests) diff --git a/server/src/http/mcp/mod.rs b/server/src/http/mcp/mod.rs index 6c36014c..f3db0176 100644 --- a/server/src/http/mcp/mod.rs +++ b/server/src/http/mcp/mod.rs @@ -308,7 +308,7 @@ fn handle_initialize(id: Option, params: &Value) -> JsonRpcResponse { "tools": {} }, "serverInfo": { - "name": "storkit", + "name": "huskies", "version": "1.0.0" } }), @@ -537,7 +537,7 @@ fn handle_tools_list(id: Option) -> JsonRpcResponse { }, { "name": "create_worktree", - "description": "Create a git worktree for a story under .storkit/worktrees/{story_id} with deterministic naming. Writes .mcp.json and runs component setup. Returns the worktree path.", + "description": "Create a git worktree for a story under .huskies/worktrees/{story_id} with deterministic naming. Writes .mcp.json and runs component setup. Returns the worktree path.", "inputSchema": { "type": "object", "properties": { @@ -551,7 +551,7 @@ fn handle_tools_list(id: Option) -> JsonRpcResponse { }, { "name": "list_worktrees", - "description": "List all worktrees under .storkit/worktrees/ for the current project.", + "description": "List all worktrees under .huskies/worktrees/ for the current project.", "inputSchema": { "type": "object", "properties": {} @@ -670,7 +670,7 @@ fn handle_tools_list(id: Option) -> JsonRpcResponse { }, { "name": "create_spike", - "description": "Create a spike file in .storkit/work/1_backlog/ with a deterministic filename and YAML front matter. Returns the spike_id.", + "description": "Create a spike file in .huskies/work/1_backlog/ with a deterministic filename and YAML front matter. Returns the spike_id.", "inputSchema": { "type": "object", "properties": { @@ -894,7 +894,7 @@ fn handle_tools_list(id: Option) -> JsonRpcResponse { }, { "name": "launch_qa_app", - "description": "Launch the app from a story's worktree for manual QA testing. Automatically assigns a free port, writes it to .storkit_port, and starts the backend server. Only one QA app instance runs at a time.", + "description": "Launch the app from a story's worktree for manual QA testing. Automatically assigns a free port, writes it to .huskies_port, and starts the backend server. Only one QA app instance runs at a time.", "inputSchema": { "type": "object", "properties": { @@ -1023,7 +1023,7 @@ fn handle_tools_list(id: Option) -> JsonRpcResponse { }, { "name": "run_command", - "description": "Execute a shell command in an agent's worktree directory. The working_dir must be inside .storkit/worktrees/. Returns stdout, stderr, exit_code, and timed_out. Supports SSE streaming (send Accept: text/event-stream) for long-running commands. Dangerous commands (rm -rf /, sudo, etc.) are blocked.", + "description": "Execute a shell command in an agent's worktree directory. The working_dir must be inside .huskies/worktrees/. Returns stdout, stderr, exit_code, and timed_out. Supports SSE streaming (send Accept: text/event-stream) for long-running commands. Dangerous commands (rm -rf /, sudo, etc.) are blocked.", "inputSchema": { "type": "object", "properties": { @@ -1033,7 +1033,7 @@ fn handle_tools_list(id: Option) -> JsonRpcResponse { }, "working_dir": { "type": "string", - "description": "Absolute path to the worktree directory to run the command in. Must be inside .storkit/worktrees/." + "description": "Absolute path to the worktree directory to run the command in. Must be inside .huskies/worktrees/." }, "timeout": { "type": "integer", @@ -1045,13 +1045,13 @@ fn handle_tools_list(id: Option) -> JsonRpcResponse { }, { "name": "git_status", - "description": "Return the working tree status of an agent's worktree (staged, unstaged, and untracked files). The worktree_path must be inside .storkit/worktrees/. Push and remote operations are not available.", + "description": "Return the working tree status of an agent's worktree (staged, unstaged, and untracked files). The worktree_path must be inside .huskies/worktrees/. Push and remote operations are not available.", "inputSchema": { "type": "object", "properties": { "worktree_path": { "type": "string", - "description": "Absolute path to the worktree directory. Must be inside .storkit/worktrees/." + "description": "Absolute path to the worktree directory. Must be inside .huskies/worktrees/." } }, "required": ["worktree_path"] @@ -1059,13 +1059,13 @@ fn handle_tools_list(id: Option) -> JsonRpcResponse { }, { "name": "git_diff", - "description": "Return diff output for an agent's worktree. Supports unstaged (default), staged, or a commit range. The worktree_path must be inside .storkit/worktrees/.", + "description": "Return diff output for an agent's worktree. Supports unstaged (default), staged, or a commit range. The worktree_path must be inside .huskies/worktrees/.", "inputSchema": { "type": "object", "properties": { "worktree_path": { "type": "string", - "description": "Absolute path to the worktree directory. Must be inside .storkit/worktrees/." + "description": "Absolute path to the worktree directory. Must be inside .huskies/worktrees/." }, "staged": { "type": "boolean", @@ -1081,13 +1081,13 @@ fn handle_tools_list(id: Option) -> JsonRpcResponse { }, { "name": "git_add", - "description": "Stage files by path in an agent's worktree. The worktree_path must be inside .storkit/worktrees/.", + "description": "Stage files by path in an agent's worktree. The worktree_path must be inside .huskies/worktrees/.", "inputSchema": { "type": "object", "properties": { "worktree_path": { "type": "string", - "description": "Absolute path to the worktree directory. Must be inside .storkit/worktrees/." + "description": "Absolute path to the worktree directory. Must be inside .huskies/worktrees/." }, "paths": { "type": "array", @@ -1100,13 +1100,13 @@ fn handle_tools_list(id: Option) -> JsonRpcResponse { }, { "name": "git_commit", - "description": "Commit staged changes in an agent's worktree with the given message. The worktree_path must be inside .storkit/worktrees/. Push and remote operations are not available.", + "description": "Commit staged changes in an agent's worktree with the given message. The worktree_path must be inside .huskies/worktrees/. Push and remote operations are not available.", "inputSchema": { "type": "object", "properties": { "worktree_path": { "type": "string", - "description": "Absolute path to the worktree directory. Must be inside .storkit/worktrees/." + "description": "Absolute path to the worktree directory. Must be inside .huskies/worktrees/." }, "message": { "type": "string", @@ -1118,13 +1118,13 @@ fn handle_tools_list(id: Option) -> JsonRpcResponse { }, { "name": "git_log", - "description": "Return commit history for an agent's worktree with configurable count and format. The worktree_path must be inside .storkit/worktrees/.", + "description": "Return commit history for an agent's worktree with configurable count and format. The worktree_path must be inside .huskies/worktrees/.", "inputSchema": { "type": "object", "properties": { "worktree_path": { "type": "string", - "description": "Absolute path to the worktree directory. Must be inside .storkit/worktrees/." + "description": "Absolute path to the worktree directory. Must be inside .huskies/worktrees/." }, "count": { "type": "integer", @@ -1363,7 +1363,7 @@ mod tests { let result = resp.result.unwrap(); assert_eq!(result["protocolVersion"], "2025-03-26"); assert!(result["capabilities"]["tools"].is_object()); - assert_eq!(result["serverInfo"]["name"], "storkit"); + assert_eq!(result["serverInfo"]["name"], "huskies"); } #[test] @@ -1638,7 +1638,7 @@ mod tests { ) .await; assert_eq!(body["result"]["protocolVersion"], "2025-03-26"); - assert_eq!(body["result"]["serverInfo"]["name"], "storkit"); + assert_eq!(body["result"]["serverInfo"]["name"], "huskies"); } #[tokio::test] diff --git a/server/src/http/mcp/qa_tools.rs b/server/src/http/mcp/qa_tools.rs index 6acea206..dc675151 100644 --- a/server/src/http/mcp/qa_tools.rs +++ b/server/src/http/mcp/qa_tools.rs @@ -48,7 +48,7 @@ pub(super) async fn tool_approve_qa(args: &Value, ctx: &AppContext) -> Result Result Result // Find a free port starting from 3100 let port = find_free_port(3100); - // Write .storkit_port so the frontend dev server knows where to connect - let port_file = wt_path.join(".storkit_port"); + // Write .huskies_port so the frontend dev server knows where to connect + let port_file = wt_path.join(".huskies_port"); std::fs::write(&port_file, port.to_string()) - .map_err(|e| format!("Failed to write .storkit_port: {e}"))?; + .map_err(|e| format!("Failed to write .huskies_port: {e}"))?; // Launch the server from the worktree let child = std::process::Command::new("cargo") .args(["run"]) - .env("STORKIT_PORT", port.to_string()) + .env("HUSKIES_PORT", port.to_string()) .current_dir(&wt_path) .stdout(std::process::Stdio::null()) .stderr(std::process::Stdio::null()) diff --git a/server/src/http/mcp/shell_tools.rs b/server/src/http/mcp/shell_tools.rs index e5fa4a13..50f8df23 100644 --- a/server/src/http/mcp/shell_tools.rs +++ b/server/src/http/mcp/shell_tools.rs @@ -59,7 +59,7 @@ fn is_dangerous(command: &str) -> Option { } /// Validates that `working_dir` exists and is inside the project's -/// `.storkit/worktrees/` directory. Returns the canonicalized path. +/// `.huskies/worktrees/` directory. Returns the canonicalized path. fn validate_working_dir(working_dir: &str, ctx: &AppContext) -> Result { let wd = PathBuf::from(working_dir); @@ -71,7 +71,7 @@ fn validate_working_dir(working_dir: &str, ctx: &AppContext) -> Result Result Vec<(String, bool)> { items } -/// Find the most recent log file for any agent under `.storkit/logs/{story_id}/`. +/// Find the most recent log file for any agent under `.huskies/logs/{story_id}/`. fn find_most_recent_log(project_root: &Path, story_id: &str) -> Option { let dir = project_root - .join(".storkit") + .join(".huskies") .join("logs") .join(story_id); @@ -157,7 +157,7 @@ pub(super) async fn tool_status(args: &Value, ctx: &AppContext) -> Result Result Result Result< } // 4. Find and delete the story file from any pipeline stage - let sk = project_root.join(".storkit").join("work"); + let sk = project_root.join(".huskies").join("work"); let stage_dirs = [ "1_backlog", "2_current", @@ -667,7 +667,7 @@ mod tests { ("4_merge", "40_story_merge", "Merge Story"), ("5_done", "50_story_done", "Done Story"), ] { - let dir = root.join(".storkit/work").join(stage); + let dir = root.join(".huskies/work").join(stage); std::fs::create_dir_all(&dir).unwrap(); std::fs::write( dir.join(format!("{id}.md")), @@ -705,7 +705,7 @@ mod tests { let tmp = tempfile::tempdir().unwrap(); let root = tmp.path(); - let current = root.join(".storkit/work/2_current"); + let current = root.join(".huskies/work/2_current"); std::fs::create_dir_all(¤t).unwrap(); std::fs::write( current.join("20_story_active.md"), @@ -745,7 +745,7 @@ mod tests { #[test] fn tool_get_story_todos_returns_unchecked() { let tmp = tempfile::tempdir().unwrap(); - let current_dir = tmp.path().join(".storkit").join("work").join("2_current"); + let current_dir = tmp.path().join(".huskies").join("work").join("2_current"); fs::create_dir_all(¤t_dir).unwrap(); fs::write( current_dir.join("1_test.md"), @@ -839,8 +839,8 @@ mod tests { "create_bug description should reference work/1_backlog/, got: {desc}" ); assert!( - !desc.contains(".storkit/bugs"), - "create_bug description should not reference nonexistent .storkit/bugs/, got: {desc}" + !desc.contains(".huskies/bugs"), + "create_bug description should not reference nonexistent .huskies/bugs/, got: {desc}" ); let required = t["inputSchema"]["required"].as_array().unwrap(); let req_names: Vec<&str> = required.iter().map(|v| v.as_str().unwrap()).collect(); @@ -865,8 +865,8 @@ mod tests { "list_bugs description should reference work/1_backlog/, got: {desc}" ); assert!( - !desc.contains(".storkit/bugs"), - "list_bugs description should not reference nonexistent .storkit/bugs/, got: {desc}" + !desc.contains(".huskies/bugs"), + "list_bugs description should not reference nonexistent .huskies/bugs/, got: {desc}" ); } @@ -880,8 +880,8 @@ mod tests { let t = tool.unwrap(); let desc = t["description"].as_str().unwrap(); assert!( - !desc.contains(".storkit/bugs"), - "close_bug description should not reference nonexistent .storkit/bugs/, got: {desc}" + !desc.contains(".huskies/bugs"), + "close_bug description should not reference nonexistent .huskies/bugs/, got: {desc}" ); assert!( desc.contains("work/5_done/"), @@ -947,7 +947,7 @@ mod tests { assert!(result.contains("1_bug_login_crash")); let bug_file = tmp .path() - .join(".storkit/work/1_backlog/1_bug_login_crash.md"); + .join(".huskies/work/1_backlog/1_bug_login_crash.md"); assert!(bug_file.exists()); } @@ -963,7 +963,7 @@ mod tests { #[test] fn tool_list_bugs_returns_open_bugs() { let tmp = tempfile::tempdir().unwrap(); - let backlog_dir = tmp.path().join(".storkit/work/1_backlog"); + let backlog_dir = tmp.path().join(".huskies/work/1_backlog"); std::fs::create_dir_all(&backlog_dir).unwrap(); std::fs::write(backlog_dir.join("1_bug_crash.md"), "# Bug 1: App Crash\n").unwrap(); std::fs::write( @@ -995,7 +995,7 @@ mod tests { fn tool_close_bug_moves_to_archive() { let tmp = tempfile::tempdir().unwrap(); setup_git_repo_in(tmp.path()); - let backlog_dir = tmp.path().join(".storkit/work/1_backlog"); + let backlog_dir = tmp.path().join(".huskies/work/1_backlog"); std::fs::create_dir_all(&backlog_dir).unwrap(); let bug_file = backlog_dir.join("1_bug_crash.md"); std::fs::write(&bug_file, "# Bug 1: Crash\n").unwrap(); @@ -1017,7 +1017,7 @@ mod tests { assert!(!bug_file.exists()); assert!( tmp.path() - .join(".storkit/work/5_done/1_bug_crash.md") + .join(".huskies/work/5_done/1_bug_crash.md") .exists() ); } @@ -1070,7 +1070,7 @@ mod tests { assert!(result.contains("1_spike_compare_encoders")); let spike_file = tmp .path() - .join(".storkit/work/1_backlog/1_spike_compare_encoders.md"); + .join(".huskies/work/1_backlog/1_spike_compare_encoders.md"); assert!(spike_file.exists()); let contents = std::fs::read_to_string(&spike_file).unwrap(); assert!(contents.starts_with("---\nname: \"Compare Encoders\"\n---")); @@ -1087,7 +1087,7 @@ mod tests { let spike_file = tmp .path() - .join(".storkit/work/1_backlog/1_spike_my_spike.md"); + .join(".huskies/work/1_backlog/1_spike_my_spike.md"); assert!(spike_file.exists()); let contents = std::fs::read_to_string(&spike_file).unwrap(); assert!(contents.starts_with("---\nname: \"My Spike\"\n---")); @@ -1130,7 +1130,7 @@ mod tests { #[test] fn tool_validate_stories_with_valid_story() { let tmp = tempfile::tempdir().unwrap(); - let current_dir = tmp.path().join(".storkit").join("work").join("2_current"); + let current_dir = tmp.path().join(".huskies").join("work").join("2_current"); fs::create_dir_all(¤t_dir).unwrap(); fs::write( current_dir.join("1_test.md"), @@ -1147,7 +1147,7 @@ mod tests { #[test] fn tool_validate_stories_with_invalid_front_matter() { let tmp = tempfile::tempdir().unwrap(); - let current_dir = tmp.path().join(".storkit").join("work").join("2_current"); + let current_dir = tmp.path().join(".huskies").join("work").join("2_current"); fs::create_dir_all(¤t_dir).unwrap(); fs::write(current_dir.join("1_test.md"), "## No front matter at all\n").unwrap(); let ctx = test_ctx(tmp.path()); @@ -1160,7 +1160,7 @@ mod tests { #[test] fn record_tests_persists_to_story_file() { let tmp = tempfile::tempdir().unwrap(); - let current = tmp.path().join(".storkit/work/2_current"); + let current = tmp.path().join(".huskies/work/2_current"); fs::create_dir_all(¤t).unwrap(); fs::write( current.join("1_story_persist.md"), @@ -1185,7 +1185,7 @@ mod tests { "file should have Test Results section" ); assert!( - contents.contains("storkit-test-results:"), + contents.contains("huskies-test-results:"), "file should have JSON marker" ); assert!(contents.contains("u1"), "file should contain test name"); @@ -1194,11 +1194,11 @@ mod tests { #[test] fn ensure_acceptance_reads_from_file_when_not_in_memory() { let tmp = tempfile::tempdir().unwrap(); - let current = tmp.path().join(".storkit/work/2_current"); + let current = tmp.path().join(".huskies/work/2_current"); fs::create_dir_all(¤t).unwrap(); // Write a story file with a pre-populated Test Results section (simulating a restart) - let story_content = "---\nname: Persist\n---\n# Story\n\n## Test Results\n\n\n"; + let story_content = "---\nname: Persist\n---\n# Story\n\n## Test Results\n\n\n"; fs::write(current.join("2_story_file_only.md"), story_content).unwrap(); // Use a fresh context (empty in-memory state, simulating a restart) @@ -1217,10 +1217,10 @@ mod tests { #[test] fn ensure_acceptance_file_with_failures_still_blocks() { let tmp = tempfile::tempdir().unwrap(); - let current = tmp.path().join(".storkit/work/2_current"); + let current = tmp.path().join(".huskies/work/2_current"); fs::create_dir_all(¤t).unwrap(); - let story_content = "---\nname: Fail\n---\n# Story\n\n## Test Results\n\n\n"; + let story_content = "---\nname: Fail\n---\n# Story\n\n## Test Results\n\n\n"; fs::write(current.join("3_story_fail.md"), story_content).unwrap(); let ctx = test_ctx(tmp.path()); @@ -1254,7 +1254,7 @@ mod tests { #[tokio::test] async fn tool_delete_story_deletes_file_from_backlog() { let tmp = tempfile::tempdir().unwrap(); - let backlog = tmp.path().join(".storkit/work/1_backlog"); + let backlog = tmp.path().join(".huskies/work/1_backlog"); fs::create_dir_all(&backlog).unwrap(); let story_file = backlog.join("10_story_cleanup.md"); fs::write(&story_file, "---\nname: Cleanup\n---\n").unwrap(); @@ -1268,7 +1268,7 @@ mod tests { #[tokio::test] async fn tool_delete_story_deletes_file_from_current() { let tmp = tempfile::tempdir().unwrap(); - let current = tmp.path().join(".storkit/work/2_current"); + let current = tmp.path().join(".huskies/work/2_current"); fs::create_dir_all(¤t).unwrap(); let story_file = current.join("11_story_active.md"); fs::write(&story_file, "---\nname: Active\n---\n").unwrap(); @@ -1328,7 +1328,7 @@ mod tests { .unwrap(); // Create story file in current/ so move_story_to_done would work. - let current_dir = tmp.path().join(".storkit/work/2_current"); + let current_dir = tmp.path().join(".huskies/work/2_current"); std::fs::create_dir_all(¤t_dir).unwrap(); std::fs::write( current_dir.join("50_story_test.md"), @@ -1356,7 +1356,7 @@ mod tests { setup_git_repo_in(tmp.path()); // Create story file in current/ (no feature branch). - let current_dir = tmp.path().join(".storkit/work/2_current"); + let current_dir = tmp.path().join(".huskies/work/2_current"); std::fs::create_dir_all(¤t_dir).unwrap(); std::fs::write( current_dir.join("51_story_no_branch.md"), @@ -1394,7 +1394,7 @@ mod tests { fn tool_check_criterion_marks_unchecked_item() { let tmp = tempfile::tempdir().unwrap(); setup_git_repo_in(tmp.path()); - let current_dir = tmp.path().join(".storkit").join("work").join("2_current"); + let current_dir = tmp.path().join(".huskies").join("work").join("2_current"); fs::create_dir_all(¤t_dir).unwrap(); fs::write( current_dir.join("1_test.md"), diff --git a/server/src/http/mcp/wizard_tools.rs b/server/src/http/mcp/wizard_tools.rs index c13f26ea..ed044365 100644 --- a/server/src/http/mcp/wizard_tools.rs +++ b/server/src/http/mcp/wizard_tools.rs @@ -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 { 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 { 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")); diff --git a/server/src/http/mod.rs b/server/src/http/mod.rs index 1b4e0995..e95834f6 100644 --- a/server/src/http/mod.rs +++ b/server/src/http/mod.rs @@ -47,11 +47,11 @@ pub fn parse_port(value: Option) -> u16 { } pub fn resolve_port() -> u16 { - parse_port(std::env::var("STORKIT_PORT").ok()) + parse_port(std::env::var("HUSKIES_PORT").ok()) } pub fn write_port_file(dir: &Path, port: u16) -> Option { - let path = dir.join(".storkit_port"); + let path = dir.join(".huskies_port"); std::fs::write(&path, port.to_string()).ok()?; Some(path) } @@ -156,7 +156,7 @@ pub fn build_openapi_service(ctx: Arc) -> (ApiService, ApiService) { ); let api_service = - OpenApiService::new(api, "Storkit API", "1.0").server("http://127.0.0.1:3001/api"); + OpenApiService::new(api, "Huskies API", "1.0").server("http://127.0.0.1:3001/api"); let docs_api = ( ProjectApi { ctx: ctx.clone() }, @@ -172,7 +172,7 @@ pub fn build_openapi_service(ctx: Arc) -> (ApiService, ApiService) { ); let docs_service = - OpenApiService::new(docs_api, "Storkit API", "1.0").server("http://127.0.0.1:3001/api"); + OpenApiService::new(docs_api, "Huskies API", "1.0").server("http://127.0.0.1:3001/api"); (api_service, docs_service) } @@ -221,7 +221,7 @@ mod tests { #[test] fn resolve_port_returns_a_valid_port() { - // Exercises the resolve_port code path (reads STORKIT_PORT env var or defaults). + // Exercises the resolve_port code path (reads HUSKIES_PORT env var or defaults). let port = resolve_port(); assert!(port > 0); } diff --git a/server/src/http/oauth.rs b/server/src/http/oauth.rs index 8932e1ae..502d45e1 100644 --- a/server/src/http/oauth.rs +++ b/server/src/http/oauth.rs @@ -289,7 +289,7 @@ pub async fn oauth_callback( html_response( StatusCode::OK, "Authenticated!", - "Claude OAuth login successful. You can close this tab and return to Storkit.", + "Claude OAuth login successful. You can close this tab and return to Huskies.", ) } diff --git a/server/src/http/settings.rs b/server/src/http/settings.rs index 5e74683f..242200da 100644 --- a/server/src/http/settings.rs +++ b/server/src/http/settings.rs @@ -237,7 +237,7 @@ mod tests { #[test] fn editor_command_survives_reload() { let dir = TempDir::new().unwrap(); - let store_path = dir.path().join(".storkit_store.json"); + let store_path = dir.path().join(".huskies_store.json"); { let ctx = AppContext::new_test(dir.path().to_path_buf()); diff --git a/server/src/http/wizard.rs b/server/src/http/wizard.rs index 8036c5bd..16ffc9ab 100644 --- a/server/src/http/wizard.rs +++ b/server/src/http/wizard.rs @@ -168,7 +168,7 @@ mod tests { fn setup() -> (TempDir, TestClient) { let dir = TempDir::new().unwrap(); 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(); let ctx = Arc::new(AppContext::new_test(root.clone())); let api = WizardApi { ctx }; diff --git a/server/src/http/workflow/bug_ops.rs b/server/src/http/workflow/bug_ops.rs index 1750e6c1..5d1fcab9 100644 --- a/server/src/http/workflow/bug_ops.rs +++ b/server/src/http/workflow/bug_ops.rs @@ -24,7 +24,7 @@ pub fn create_bug_file( } let filename = format!("{bug_number}_bug_{slug}.md"); - let bugs_dir = root.join(".storkit").join("work").join("1_backlog"); + let bugs_dir = root.join(".huskies").join("work").join("1_backlog"); fs::create_dir_all(&bugs_dir) .map_err(|e| format!("Failed to create backlog directory: {e}"))?; @@ -88,7 +88,7 @@ pub fn create_spike_file( } let filename = format!("{spike_number}_spike_{slug}.md"); - let backlog_dir = root.join(".storkit").join("work").join("1_backlog"); + let backlog_dir = root.join(".huskies").join("work").join("1_backlog"); fs::create_dir_all(&backlog_dir) .map_err(|e| format!("Failed to create backlog directory: {e}"))?; @@ -151,7 +151,7 @@ pub fn create_refactor_file( } let filename = format!("{refactor_number}_refactor_{slug}.md"); - let backlog_dir = root.join(".storkit").join("work").join("1_backlog"); + let backlog_dir = root.join(".huskies").join("work").join("1_backlog"); fs::create_dir_all(&backlog_dir) .map_err(|e| format!("Failed to create backlog directory: {e}"))?; @@ -227,7 +227,7 @@ fn extract_bug_name(path: &Path) -> Option { /// /// Returns a sorted list of `(bug_id, name)` pairs. pub fn list_bug_files(root: &Path) -> Result, String> { - let backlog_dir = root.join(".storkit").join("work").join("1_backlog"); + let backlog_dir = root.join(".huskies").join("work").join("1_backlog"); if !backlog_dir.exists() { return Ok(Vec::new()); } @@ -277,7 +277,7 @@ fn is_refactor_item(stem: &str) -> bool { /// /// Returns a sorted list of `(refactor_id, name)` pairs. pub fn list_refactor_files(root: &Path) -> Result, String> { - let backlog_dir = root.join(".storkit").join("work").join("1_backlog"); + let backlog_dir = root.join(".huskies").join("work").join("1_backlog"); if !backlog_dir.exists() { return Ok(Vec::new()); } @@ -357,7 +357,7 @@ mod tests { #[test] fn next_item_number_increments_from_existing_bugs() { let tmp = tempfile::tempdir().unwrap(); - let backlog = tmp.path().join(".storkit/work/1_backlog"); + let backlog = tmp.path().join(".huskies/work/1_backlog"); fs::create_dir_all(&backlog).unwrap(); fs::write(backlog.join("1_bug_crash.md"), "").unwrap(); fs::write(backlog.join("3_bug_another.md"), "").unwrap(); @@ -367,8 +367,8 @@ mod tests { #[test] fn next_item_number_scans_archived_too() { let tmp = tempfile::tempdir().unwrap(); - let backlog = tmp.path().join(".storkit/work/1_backlog"); - let archived = tmp.path().join(".storkit/work/5_done"); + let backlog = tmp.path().join(".huskies/work/1_backlog"); + let archived = tmp.path().join(".huskies/work/5_done"); fs::create_dir_all(&backlog).unwrap(); fs::create_dir_all(&archived).unwrap(); fs::write(archived.join("5_bug_old.md"), "").unwrap(); @@ -385,8 +385,8 @@ mod tests { #[test] fn list_bug_files_excludes_archive_subdir() { let tmp = tempfile::tempdir().unwrap(); - let backlog_dir = tmp.path().join(".storkit/work/1_backlog"); - let archived_dir = tmp.path().join(".storkit/work/5_done"); + let backlog_dir = tmp.path().join(".huskies/work/1_backlog"); + let archived_dir = tmp.path().join(".huskies/work/5_done"); fs::create_dir_all(&backlog_dir).unwrap(); fs::create_dir_all(&archived_dir).unwrap(); fs::write(backlog_dir.join("1_bug_open.md"), "# Bug 1: Open Bug\n").unwrap(); @@ -401,7 +401,7 @@ mod tests { #[test] fn list_bug_files_sorted_by_id() { let tmp = tempfile::tempdir().unwrap(); - let backlog_dir = tmp.path().join(".storkit/work/1_backlog"); + let backlog_dir = tmp.path().join(".huskies/work/1_backlog"); fs::create_dir_all(&backlog_dir).unwrap(); fs::write(backlog_dir.join("3_bug_third.md"), "# Bug 3: Third\n").unwrap(); fs::write(backlog_dir.join("1_bug_first.md"), "# Bug 1: First\n").unwrap(); @@ -443,7 +443,7 @@ mod tests { let filepath = tmp .path() - .join(".storkit/work/1_backlog/1_bug_login_crash.md"); + .join(".huskies/work/1_backlog/1_bug_login_crash.md"); assert!(filepath.exists()); let contents = fs::read_to_string(&filepath).unwrap(); assert!( @@ -487,7 +487,7 @@ mod tests { ) .unwrap(); - let filepath = tmp.path().join(".storkit/work/1_backlog/1_bug_some_bug.md"); + let filepath = tmp.path().join(".huskies/work/1_backlog/1_bug_some_bug.md"); let contents = fs::read_to_string(&filepath).unwrap(); assert!( contents.starts_with("---\nname: \"Some Bug\"\n---"), @@ -509,7 +509,7 @@ mod tests { let filepath = tmp .path() - .join(".storkit/work/1_backlog/1_spike_filesystem_watcher_architecture.md"); + .join(".huskies/work/1_backlog/1_spike_filesystem_watcher_architecture.md"); assert!(filepath.exists()); let contents = fs::read_to_string(&filepath).unwrap(); assert!( @@ -533,7 +533,7 @@ mod tests { create_spike_file(tmp.path(), "FS Watcher Spike", Some(description)).unwrap(); let filepath = - tmp.path().join(".storkit/work/1_backlog/1_spike_fs_watcher_spike.md"); + tmp.path().join(".huskies/work/1_backlog/1_spike_fs_watcher_spike.md"); let contents = fs::read_to_string(&filepath).unwrap(); assert!(contents.contains(description)); } @@ -543,7 +543,7 @@ mod tests { let tmp = tempfile::tempdir().unwrap(); create_spike_file(tmp.path(), "My Spike", None).unwrap(); - let filepath = tmp.path().join(".storkit/work/1_backlog/1_spike_my_spike.md"); + let filepath = tmp.path().join(".huskies/work/1_backlog/1_spike_my_spike.md"); let contents = fs::read_to_string(&filepath).unwrap(); // Should have placeholder TBD in Question section assert!(contents.contains("## Question\n\n- TBD\n")); @@ -564,7 +564,7 @@ mod tests { let result = create_spike_file(tmp.path(), name, None); assert!(result.is_ok(), "create_spike_file failed: {result:?}"); - let backlog = tmp.path().join(".storkit/work/1_backlog"); + let backlog = tmp.path().join(".huskies/work/1_backlog"); let spike_id = result.unwrap(); let filename = format!("{spike_id}.md"); let contents = fs::read_to_string(backlog.join(&filename)).unwrap(); @@ -576,7 +576,7 @@ mod tests { #[test] fn create_spike_file_increments_from_existing_items() { let tmp = tempfile::tempdir().unwrap(); - let backlog = tmp.path().join(".storkit/work/1_backlog"); + let backlog = tmp.path().join(".huskies/work/1_backlog"); fs::create_dir_all(&backlog).unwrap(); fs::write(backlog.join("5_story_existing.md"), "").unwrap(); diff --git a/server/src/http/workflow/mod.rs b/server/src/http/workflow/mod.rs index 14466dde..cf64a0f5 100644 --- a/server/src/http/workflow/mod.rs +++ b/server/src/http/workflow/mod.rs @@ -121,7 +121,7 @@ fn load_stage_items( agent_map: &HashMap, ) -> Result, String> { let root = ctx.state.get_project_root()?; - let dir = root.join(".storkit").join("work").join(stage_dir); + let dir = root.join(".huskies").join("work").join(stage_dir); if !dir.exists() { return Ok(Vec::new()); @@ -166,8 +166,8 @@ pub fn validate_story_dirs( // Directories to validate: work/2_current/ + work/1_backlog/ let dirs_to_validate: Vec = vec![ - root.join(".storkit").join("work").join("2_current"), - root.join(".storkit").join("work").join("1_backlog"), + root.join(".huskies").join("work").join("2_current"), + root.join(".huskies").join("work").join("1_backlog"), ]; for dir in &dirs_to_validate { @@ -230,7 +230,7 @@ pub fn validate_story_dirs( /// Searches in priority order: 2_current, 1_backlog, 3_qa, 4_merge, 5_done, 6_archived. pub(super) fn find_story_file(project_root: &Path, story_id: &str) -> Result { let filename = format!("{story_id}.md"); - let sk = project_root.join(".storkit").join("work"); + let sk = project_root.join(".huskies").join("work"); for stage in &["2_current", "1_backlog", "3_qa", "4_merge", "5_done", "6_archived"] { let path = sk.join(stage).join(&filename); if path.exists() { @@ -370,7 +370,7 @@ pub(super) fn slugify_name(name: &str) -> String { /// Scan all `work/` subdirectories for the highest item number across all types (stories, bugs, spikes). pub(super) fn next_item_number(root: &std::path::Path) -> Result { - let work_base = root.join(".storkit").join("work"); + let work_base = root.join(".huskies").join("work"); let mut max_num: u32 = 0; for subdir in &["1_backlog", "2_current", "3_qa", "4_merge", "5_done", "6_archived"] { @@ -413,7 +413,7 @@ mod tests { ("4_merge", "40_story_merge"), ("5_done", "50_story_done"), ] { - let dir = root.join(".storkit").join("work").join(stage); + let dir = root.join(".huskies").join("work").join(stage); fs::create_dir_all(&dir).unwrap(); fs::write( dir.join(format!("{id}.md")), @@ -445,7 +445,7 @@ mod tests { fn load_upcoming_returns_empty_when_no_dir() { let tmp = tempfile::tempdir().unwrap(); let root = tmp.path().to_path_buf(); - // No .storkit directory at all + // No .huskies directory at all let ctx = crate::http::context::AppContext::new_test(root); let result = load_upcoming_stories(&ctx).unwrap(); assert!(result.is_empty()); @@ -456,7 +456,7 @@ mod tests { let tmp = tempfile::tempdir().unwrap(); let root = tmp.path().to_path_buf(); - let current = root.join(".storkit/work/2_current"); + let current = root.join(".huskies/work/2_current"); fs::create_dir_all(¤t).unwrap(); fs::write( current.join("10_story_test.md"), @@ -482,7 +482,7 @@ mod tests { let tmp = tempfile::tempdir().unwrap(); let root = tmp.path().to_path_buf(); - let current = root.join(".storkit/work/2_current"); + let current = root.join(".huskies/work/2_current"); fs::create_dir_all(¤t).unwrap(); fs::write( current.join("11_story_done.md"), @@ -507,7 +507,7 @@ mod tests { let tmp = tempfile::tempdir().unwrap(); let root = tmp.path().to_path_buf(); - let current = root.join(".storkit/work/2_current"); + let current = root.join(".huskies/work/2_current"); fs::create_dir_all(¤t).unwrap(); fs::write( current.join("12_story_pending.md"), @@ -529,7 +529,7 @@ mod tests { #[test] fn load_upcoming_parses_metadata() { let tmp = tempfile::tempdir().unwrap(); - let backlog = tmp.path().join(".storkit/work/1_backlog"); + let backlog = tmp.path().join(".huskies/work/1_backlog"); fs::create_dir_all(&backlog).unwrap(); fs::write( backlog.join("31_story_view_upcoming.md"), @@ -554,7 +554,7 @@ mod tests { #[test] fn load_upcoming_skips_non_md_files() { let tmp = tempfile::tempdir().unwrap(); - let backlog = tmp.path().join(".storkit/work/1_backlog"); + let backlog = tmp.path().join(".huskies/work/1_backlog"); fs::create_dir_all(&backlog).unwrap(); fs::write(backlog.join(".gitkeep"), "").unwrap(); fs::write( @@ -572,8 +572,8 @@ mod tests { #[test] fn validate_story_dirs_valid_files() { let tmp = tempfile::tempdir().unwrap(); - let current = tmp.path().join(".storkit/work/2_current"); - let backlog = tmp.path().join(".storkit/work/1_backlog"); + let current = tmp.path().join(".huskies/work/2_current"); + let backlog = tmp.path().join(".huskies/work/1_backlog"); fs::create_dir_all(¤t).unwrap(); fs::create_dir_all(&backlog).unwrap(); fs::write( @@ -596,7 +596,7 @@ mod tests { #[test] fn validate_story_dirs_missing_front_matter() { let tmp = tempfile::tempdir().unwrap(); - let current = tmp.path().join(".storkit/work/2_current"); + let current = tmp.path().join(".huskies/work/2_current"); fs::create_dir_all(¤t).unwrap(); fs::write(current.join("28_story_todos.md"), "# No front matter\n").unwrap(); @@ -609,7 +609,7 @@ mod tests { #[test] fn validate_story_dirs_missing_required_fields() { let tmp = tempfile::tempdir().unwrap(); - let current = tmp.path().join(".storkit/work/2_current"); + let current = tmp.path().join(".huskies/work/2_current"); fs::create_dir_all(¤t).unwrap(); fs::write(current.join("28_story_todos.md"), "---\n---\n# Story\n").unwrap(); @@ -667,7 +667,7 @@ mod tests { #[test] fn next_item_number_empty_dirs() { let tmp = tempfile::tempdir().unwrap(); - let base = tmp.path().join(".storkit/work/1_backlog"); + let base = tmp.path().join(".huskies/work/1_backlog"); fs::create_dir_all(&base).unwrap(); assert_eq!(next_item_number(tmp.path()).unwrap(), 1); } @@ -675,9 +675,9 @@ mod tests { #[test] fn next_item_number_scans_all_dirs() { let tmp = tempfile::tempdir().unwrap(); - let backlog = tmp.path().join(".storkit/work/1_backlog"); - let current = tmp.path().join(".storkit/work/2_current"); - let archived = tmp.path().join(".storkit/work/5_done"); + let backlog = tmp.path().join(".huskies/work/1_backlog"); + let current = tmp.path().join(".huskies/work/2_current"); + let archived = tmp.path().join(".huskies/work/5_done"); fs::create_dir_all(&backlog).unwrap(); fs::create_dir_all(¤t).unwrap(); fs::create_dir_all(&archived).unwrap(); @@ -690,7 +690,7 @@ mod tests { #[test] fn next_item_number_no_work_dirs() { let tmp = tempfile::tempdir().unwrap(); - // No .storkit at all + // No .huskies at all assert_eq!(next_item_number(tmp.path()).unwrap(), 1); } @@ -699,8 +699,8 @@ mod tests { #[test] fn find_story_file_searches_current_then_backlog() { let tmp = tempfile::tempdir().unwrap(); - let current = tmp.path().join(".storkit/work/2_current"); - let backlog = tmp.path().join(".storkit/work/1_backlog"); + let current = tmp.path().join(".huskies/work/2_current"); + let backlog = tmp.path().join(".huskies/work/1_backlog"); fs::create_dir_all(¤t).unwrap(); fs::create_dir_all(&backlog).unwrap(); diff --git a/server/src/http/workflow/story_ops.rs b/server/src/http/workflow/story_ops.rs index fa90d0c8..81f78e87 100644 --- a/server/src/http/workflow/story_ops.rs +++ b/server/src/http/workflow/story_ops.rs @@ -24,7 +24,7 @@ pub fn create_story_file( } let filename = format!("{story_number}_story_{slug}.md"); - let backlog_dir = root.join(".storkit").join("work").join("1_backlog"); + let backlog_dir = root.join(".huskies").join("work").join("1_backlog"); fs::create_dir_all(&backlog_dir) .map_err(|e| format!("Failed to create backlog directory: {e}"))?; @@ -281,7 +281,7 @@ mod tests { #[test] fn create_story_writes_correct_content() { let tmp = tempfile::tempdir().unwrap(); - let backlog = tmp.path().join(".storkit/work/1_backlog"); + let backlog = tmp.path().join(".huskies/work/1_backlog"); fs::create_dir_all(&backlog).unwrap(); fs::write(backlog.join("36_story_existing.md"), "").unwrap(); @@ -324,7 +324,7 @@ mod tests { let result = create_story_file(tmp.path(), name, None, None, false); assert!(result.is_ok(), "create_story_file failed: {result:?}"); - let backlog = tmp.path().join(".storkit/work/1_backlog"); + let backlog = tmp.path().join(".huskies/work/1_backlog"); let story_id = result.unwrap(); let filename = format!("{story_id}.md"); let contents = fs::read_to_string(backlog.join(&filename)).unwrap(); @@ -336,7 +336,7 @@ mod tests { #[test] fn create_story_rejects_duplicate() { let tmp = tempfile::tempdir().unwrap(); - let backlog = tmp.path().join(".storkit/work/1_backlog"); + let backlog = tmp.path().join(".huskies/work/1_backlog"); fs::create_dir_all(&backlog).unwrap(); let filepath = backlog.join("1_story_my_feature.md"); @@ -352,7 +352,7 @@ mod tests { fn check_criterion_marks_first_unchecked() { let tmp = tempfile::tempdir().unwrap(); setup_git_repo(tmp.path()); - let current = tmp.path().join(".storkit/work/2_current"); + let current = tmp.path().join(".huskies/work/2_current"); fs::create_dir_all(¤t).unwrap(); let filepath = current.join("1_test.md"); fs::write(&filepath, story_with_criteria(3)).unwrap(); @@ -379,7 +379,7 @@ mod tests { fn check_criterion_marks_second_unchecked() { let tmp = tempfile::tempdir().unwrap(); setup_git_repo(tmp.path()); - let current = tmp.path().join(".storkit/work/2_current"); + let current = tmp.path().join(".huskies/work/2_current"); fs::create_dir_all(¤t).unwrap(); let filepath = current.join("2_test.md"); fs::write(&filepath, story_with_criteria(3)).unwrap(); @@ -406,7 +406,7 @@ mod tests { fn check_criterion_out_of_range_returns_error() { let tmp = tempfile::tempdir().unwrap(); setup_git_repo(tmp.path()); - let current = tmp.path().join(".storkit/work/2_current"); + let current = tmp.path().join(".huskies/work/2_current"); fs::create_dir_all(¤t).unwrap(); let filepath = current.join("3_test.md"); fs::write(&filepath, story_with_criteria(2)).unwrap(); @@ -440,7 +440,7 @@ mod tests { #[test] fn add_criterion_appends_after_last_criterion() { let tmp = tempfile::tempdir().unwrap(); - let current = tmp.path().join(".storkit/work/2_current"); + let current = tmp.path().join(".huskies/work/2_current"); fs::create_dir_all(¤t).unwrap(); let filepath = current.join("10_test.md"); fs::write(&filepath, story_with_ac_section(&["First", "Second"])).unwrap(); @@ -460,7 +460,7 @@ mod tests { #[test] fn add_criterion_to_empty_section() { let tmp = tempfile::tempdir().unwrap(); - let current = tmp.path().join(".storkit/work/2_current"); + let current = tmp.path().join(".huskies/work/2_current"); fs::create_dir_all(¤t).unwrap(); let filepath = current.join("11_test.md"); let content = "---\nname: Test\n---\n\n## Acceptance Criteria\n\n## Out of Scope\n\n- N/A\n"; @@ -475,7 +475,7 @@ mod tests { #[test] fn add_criterion_missing_section_returns_error() { let tmp = tempfile::tempdir().unwrap(); - let current = tmp.path().join(".storkit/work/2_current"); + let current = tmp.path().join(".huskies/work/2_current"); fs::create_dir_all(¤t).unwrap(); let filepath = current.join("12_test.md"); fs::write(&filepath, "---\nname: Test\n---\n\nNo AC section here.\n").unwrap(); @@ -490,7 +490,7 @@ mod tests { #[test] fn update_story_replaces_user_story_section() { let tmp = tempfile::tempdir().unwrap(); - let current = tmp.path().join(".storkit/work/2_current"); + let current = tmp.path().join(".huskies/work/2_current"); fs::create_dir_all(¤t).unwrap(); let filepath = current.join("20_test.md"); let content = "---\nname: T\n---\n\n## User Story\n\nOld text\n\n## Acceptance Criteria\n\n- [ ] AC\n"; @@ -507,7 +507,7 @@ mod tests { #[test] fn update_story_replaces_description_section() { let tmp = tempfile::tempdir().unwrap(); - let current = tmp.path().join(".storkit/work/2_current"); + let current = tmp.path().join(".huskies/work/2_current"); fs::create_dir_all(¤t).unwrap(); let filepath = current.join("21_test.md"); let content = "---\nname: T\n---\n\n## Description\n\nOld description\n\n## Acceptance Criteria\n\n- [ ] AC\n"; @@ -523,7 +523,7 @@ mod tests { #[test] fn update_story_no_args_returns_error() { let tmp = tempfile::tempdir().unwrap(); - let current = tmp.path().join(".storkit/work/2_current"); + let current = tmp.path().join(".huskies/work/2_current"); fs::create_dir_all(¤t).unwrap(); fs::write(current.join("22_test.md"), "---\nname: T\n---\n").unwrap(); @@ -535,7 +535,7 @@ mod tests { #[test] fn update_story_missing_section_returns_error() { let tmp = tempfile::tempdir().unwrap(); - let current = tmp.path().join(".storkit/work/2_current"); + let current = tmp.path().join(".huskies/work/2_current"); fs::create_dir_all(¤t).unwrap(); fs::write( current.join("23_test.md"), @@ -551,7 +551,7 @@ mod tests { #[test] fn update_story_sets_agent_front_matter_field() { let tmp = tempfile::tempdir().unwrap(); - let current = tmp.path().join(".storkit/work/2_current"); + let current = tmp.path().join(".huskies/work/2_current"); fs::create_dir_all(¤t).unwrap(); let filepath = current.join("24_test.md"); fs::write(&filepath, "---\nname: T\n---\n\n## User Story\n\nSome story\n").unwrap(); @@ -568,7 +568,7 @@ mod tests { #[test] fn update_story_sets_arbitrary_front_matter_fields() { let tmp = tempfile::tempdir().unwrap(); - let current = tmp.path().join(".storkit/work/2_current"); + let current = tmp.path().join(".huskies/work/2_current"); fs::create_dir_all(¤t).unwrap(); let filepath = current.join("25_test.md"); fs::write(&filepath, "---\nname: T\n---\n\n## User Story\n\nSome story\n").unwrap(); @@ -587,7 +587,7 @@ mod tests { #[test] fn update_story_front_matter_only_no_section_required() { let tmp = tempfile::tempdir().unwrap(); - let current = tmp.path().join(".storkit/work/2_current"); + let current = tmp.path().join(".huskies/work/2_current"); fs::create_dir_all(¤t).unwrap(); // File without a User Story section — front matter update should succeed let filepath = current.join("26_test.md"); @@ -605,7 +605,7 @@ mod tests { #[test] fn update_story_bool_front_matter_written_unquoted() { let tmp = tempfile::tempdir().unwrap(); - let current = tmp.path().join(".storkit/work/2_current"); + let current = tmp.path().join(".huskies/work/2_current"); fs::create_dir_all(¤t).unwrap(); let filepath = current.join("27_test.md"); fs::write(&filepath, "---\nname: T\n---\n\nNo sections.\n").unwrap(); @@ -622,7 +622,7 @@ mod tests { #[test] fn update_story_integer_front_matter_written_unquoted() { let tmp = tempfile::tempdir().unwrap(); - let current = tmp.path().join(".storkit/work/2_current"); + let current = tmp.path().join(".huskies/work/2_current"); fs::create_dir_all(¤t).unwrap(); let filepath = current.join("28_test.md"); fs::write(&filepath, "---\nname: T\n---\n\nNo sections.\n").unwrap(); @@ -639,7 +639,7 @@ mod tests { #[test] fn update_story_bool_front_matter_parseable_after_write() { let tmp = tempfile::tempdir().unwrap(); - let current = tmp.path().join(".storkit/work/2_current"); + let current = tmp.path().join(".huskies/work/2_current"); fs::create_dir_all(¤t).unwrap(); let filepath = current.join("29_test.md"); fs::write(&filepath, "---\nname: My Story\n---\n\nNo sections.\n").unwrap(); diff --git a/server/src/http/workflow/test_results.rs b/server/src/http/workflow/test_results.rs index f3fcc9ea..37b8fcf9 100644 --- a/server/src/http/workflow/test_results.rs +++ b/server/src/http/workflow/test_results.rs @@ -5,7 +5,7 @@ use std::path::Path; use super::{find_story_file, replace_or_append_section}; -const TEST_RESULTS_MARKER: &str = "\n\n### Unit Tests (0 passed, 0 failed)\n\n*No unit tests recorded.*\n", + "---\nname: Overwrite\n---\n# Story\n\n## Test Results\n\n\n\n### Unit Tests (0 passed, 0 failed)\n\n*No unit tests recorded.*\n", ) .unwrap(); @@ -233,7 +233,7 @@ mod tests { #[test] fn read_test_results_returns_none_when_no_section() { let tmp = tempfile::tempdir().unwrap(); - let current = tmp.path().join(".storkit/work/2_current"); + let current = tmp.path().join(".huskies/work/2_current"); fs::create_dir_all(¤t).unwrap(); fs::write( current.join("4_story_empty.md"), @@ -255,7 +255,7 @@ mod tests { #[test] fn write_test_results_finds_story_in_any_stage() { let tmp = tempfile::tempdir().unwrap(); - let qa_dir = tmp.path().join(".storkit/work/3_qa"); + let qa_dir = tmp.path().join(".huskies/work/3_qa"); fs::create_dir_all(&qa_dir).unwrap(); fs::write( qa_dir.join("5_story_qa.md"), @@ -280,7 +280,7 @@ mod tests { #[test] fn write_coverage_baseline_to_story_file_updates_front_matter() { let tmp = tempfile::tempdir().unwrap(); - let current = tmp.path().join(".storkit/work/2_current"); + let current = tmp.path().join(".huskies/work/2_current"); fs::create_dir_all(¤t).unwrap(); fs::write( current.join("6_story_cov.md"), diff --git a/server/src/http/ws.rs b/server/src/http/ws.rs index d775a4c0..cab0e272 100644 --- a/server/src/http/ws.rs +++ b/server/src/http/ws.rs @@ -64,8 +64,8 @@ pub struct WizardStepInfo { /// - `token` streams partial model output. /// - `update` pushes the updated message history. /// - `error` reports a request or processing failure. -/// - `work_item_changed` notifies that a `.storkit/work/` file changed. -/// - `agent_config_changed` notifies that `.storkit/project.toml` was modified. +/// - `work_item_changed` notifies that a `.huskies/work/` file changed. +/// - `agent_config_changed` notifies that `.huskies/project.toml` was modified. enum WsResponse { Token { content: String, @@ -97,7 +97,7 @@ enum WsResponse { merge: Vec, done: Vec, }, - /// `.storkit/project.toml` was modified; the frontend should re-fetch the + /// `.huskies/project.toml` was modified; the frontend should re-fetch the /// agent roster. Does NOT trigger a pipeline state refresh. AgentConfigChanged, /// An agent's state changed (started, stopped, completed, etc.). @@ -773,14 +773,14 @@ mod tests { stage: "2_current".to_string(), item_id: "42_story_foo".to_string(), action: "start".to_string(), - commit_msg: "storkit: start 42_story_foo".to_string(), + commit_msg: "huskies: start 42_story_foo".to_string(), }; let json = serde_json::to_value(&resp).unwrap(); assert_eq!(json["type"], "work_item_changed"); assert_eq!(json["stage"], "2_current"); assert_eq!(json["item_id"], "42_story_foo"); assert_eq!(json["action"], "start"); - assert_eq!(json["commit_msg"], "storkit: start 42_story_foo"); + assert_eq!(json["commit_msg"], "huskies: start 42_story_foo"); } #[test] @@ -901,7 +901,7 @@ mod tests { stage: "2_current".to_string(), item_id: "42_story_foo".to_string(), action: "start".to_string(), - commit_msg: "storkit: start 42_story_foo".to_string(), + commit_msg: "huskies: start 42_story_foo".to_string(), from_stage: None, }; let ws_msg: Option = evt.into(); @@ -1166,7 +1166,7 @@ mod tests { // Create minimal pipeline dirs so load_pipeline_state succeeds. for stage in &["1_backlog", "2_current", "3_qa", "4_merge"] { - std::fs::create_dir_all(root.join(".storkit").join("work").join(stage)).unwrap(); + std::fs::create_dir_all(root.join(".huskies").join("work").join(stage)).unwrap(); } let ctx = Arc::new(AppContext::new_test(root)); @@ -1381,7 +1381,7 @@ mod tests { stage: "2_current".to_string(), item_id: "99_story_test".to_string(), action: "start".to_string(), - commit_msg: "storkit: start 99_story_test".to_string(), + commit_msg: "huskies: start 99_story_test".to_string(), from_stage: None, }) .unwrap(); diff --git a/server/src/io/fs/paths.rs b/server/src/io/fs/paths.rs index e09bd076..865555f5 100644 --- a/server/src/io/fs/paths.rs +++ b/server/src/io/fs/paths.rs @@ -15,11 +15,11 @@ pub fn resolve_cli_path(cwd: &Path, path_arg: &str) -> PathBuf { } /// Walk from `start` up through parent directories, returning the first -/// directory that contains a `.storkit/` subdirectory, or `None`. +/// directory that contains a `.huskies/` subdirectory, or `None`. pub fn find_story_kit_root(start: &Path) -> Option { let mut current = start.to_path_buf(); loop { - if current.join(".storkit").is_dir() { + if current.join(".huskies").is_dir() { return Some(current); } if !current.pop() { @@ -79,7 +79,7 @@ mod tests { #[test] fn find_story_kit_root_returns_cwd_when_story_kit_in_cwd() { let tmp = tempfile::tempdir().unwrap(); - std::fs::create_dir_all(tmp.path().join(".storkit")).unwrap(); + std::fs::create_dir_all(tmp.path().join(".huskies")).unwrap(); let result = find_story_kit_root(tmp.path()); assert_eq!(result, Some(tmp.path().to_path_buf())); @@ -88,7 +88,7 @@ mod tests { #[test] fn find_story_kit_root_returns_parent_when_story_kit_in_parent() { let tmp = tempfile::tempdir().unwrap(); - std::fs::create_dir_all(tmp.path().join(".storkit")).unwrap(); + std::fs::create_dir_all(tmp.path().join(".huskies")).unwrap(); let child = tmp.path().join("subdir").join("nested"); std::fs::create_dir_all(&child).unwrap(); @@ -107,9 +107,9 @@ mod tests { #[test] fn find_story_kit_root_prefers_nearest_ancestor() { let tmp = tempfile::tempdir().unwrap(); - std::fs::create_dir_all(tmp.path().join(".storkit")).unwrap(); + std::fs::create_dir_all(tmp.path().join(".huskies")).unwrap(); let child = tmp.path().join("inner"); - std::fs::create_dir_all(child.join(".storkit")).unwrap(); + std::fs::create_dir_all(child.join(".huskies")).unwrap(); let result = find_story_kit_root(&child); assert_eq!(result, Some(child)); diff --git a/server/src/io/fs/project.rs b/server/src/io/fs/project.rs index 874caa4c..42fcba8b 100644 --- a/server/src/io/fs/project.rs +++ b/server/src/io/fs/project.rs @@ -33,7 +33,7 @@ pub(crate) async fn ensure_project_root_with_story_kit( fs::create_dir_all(&path) .map_err(|e| format!("Failed to create project directory: {}", e))?; } - if !path.join(".storkit").is_dir() { + if !path.join(".huskies").is_dir() { scaffold_story_kit(&path, port)?; } Ok(()) @@ -230,9 +230,9 @@ mod tests { assert!(content.contains("localhost"), "mcp.json should reference localhost"); } - /// Regression test for bug 371: no-arg `storkit` in empty directory skips scaffold. - /// `open_project` on a directory without `.storkit/` must create all required scaffold - /// files — the same files that `storkit .` produces. + /// Regression test for bug 371: no-arg `huskies` in empty directory skips scaffold. + /// `open_project` on a directory without `.huskies/` must create all required scaffold + /// files — the same files that `huskies .` produces. #[tokio::test] async fn open_project_on_empty_dir_creates_full_scaffold() { let dir = tempdir().unwrap(); @@ -246,8 +246,8 @@ mod tests { .unwrap(); assert!( - project_dir.join(".storkit/project.toml").exists(), - "open_project must create .storkit/project.toml" + project_dir.join(".huskies/project.toml").exists(), + "open_project must create .huskies/project.toml" ); assert!( project_dir.join(".mcp.json").exists(), @@ -386,15 +386,15 @@ mod tests { .await .unwrap(); - // .storkit/ should have been created automatically - assert!(project_dir.join(".storkit").is_dir()); + // .huskies/ should have been created automatically + assert!(project_dir.join(".huskies").is_dir()); } #[tokio::test] async fn open_project_does_not_overwrite_existing_story_kit() { let dir = tempdir().unwrap(); let project_dir = dir.path().join("myproject"); - let sk_dir = project_dir.join(".storkit"); + let sk_dir = project_dir.join(".huskies"); fs::create_dir_all(&sk_dir).unwrap(); let readme = sk_dir.join("README.md"); fs::write(&readme, "custom content").unwrap(); @@ -405,7 +405,7 @@ mod tests { .await .unwrap(); - // Existing .storkit/ content should not be overwritten + // Existing .huskies/ content should not be overwritten assert_eq!(fs::read_to_string(&readme).unwrap(), "custom content"); } } diff --git a/server/src/io/fs/scaffold.rs b/server/src/io/fs/scaffold.rs index 6d4fdb02..10da8344 100644 --- a/server/src/io/fs/scaffold.rs +++ b/server/src/io/fs/scaffold.rs @@ -1,17 +1,17 @@ use std::fs; use std::path::Path; -const STORY_KIT_README: &str = include_str!("../../../../.storkit/README.md"); +const STORY_KIT_README: &str = include_str!("../../../../.huskies/README.md"); const BOT_TOML_MATRIX_EXAMPLE: &str = - include_str!("../../../../.storkit/bot.toml.matrix.example"); + include_str!("../../../../.huskies/bot.toml.matrix.example"); const BOT_TOML_WHATSAPP_META_EXAMPLE: &str = - include_str!("../../../../.storkit/bot.toml.whatsapp-meta.example"); + include_str!("../../../../.huskies/bot.toml.whatsapp-meta.example"); const BOT_TOML_WHATSAPP_TWILIO_EXAMPLE: &str = - include_str!("../../../../.storkit/bot.toml.whatsapp-twilio.example"); -const BOT_TOML_SLACK_EXAMPLE: &str = include_str!("../../../../.storkit/bot.toml.slack.example"); + include_str!("../../../../.huskies/bot.toml.whatsapp-twilio.example"); +const BOT_TOML_SLACK_EXAMPLE: &str = include_str!("../../../../.huskies/bot.toml.slack.example"); -const STORY_KIT_CONTEXT: &str = "\n\ +const STORY_KIT_CONTEXT: &str = "\n\ # Project Context\n\ \n\ ## High-Level Goal\n\ @@ -30,7 +30,7 @@ TODO: Define the key domain concepts and entities.\n\ \n\ TODO: Define abbreviations and technical terms.\n"; -const STORY_KIT_STACK: &str = "\n\ +const STORY_KIT_STACK: &str = "\n\ # Tech Stack & Constraints\n\ \n\ ## Core Stack\n\ @@ -51,16 +51,16 @@ 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_CLAUDE_MD: &str = "\n\ +const STORY_KIT_CLAUDE_MD: &str = "\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 .storkit/README.md to see our dev process.\n\ +Read .huskies/README.md to see our dev process.\n\ \n\ IMPORTANT: On your first conversation, call `wizard_status` to check if \ -project setup is complete. If not, read .storkit/README.md for the full \ +project setup is complete. If not, read .huskies/README.md for the full \ setup wizard instructions and guide the user through it conversationally.\n"; const STORY_KIT_CLAUDE_SETTINGS: &str = r#"{ @@ -94,11 +94,11 @@ const STORY_KIT_CLAUDE_SETTINGS: &str = r#"{ "Bash(./script/test:*)", "Edit", "Write", - "mcp__storkit__*" + "mcp__huskies__*" ] }, "enabledMcpjsonServers": [ - "storkit" + "huskies" ] } "#; @@ -114,7 +114,7 @@ role = "Full-stack engineer. Implements features across all components." model = "sonnet" max_turns = 50 max_budget_usd = 5.00 -prompt = "You are working in a git worktree on story {{story_id}}. Read CLAUDE.md first, then .storkit/README.md to understand the dev process. Follow the workflow through implementation and verification. The worktree and feature branch already exist - do not create them. Check .mcp.json for MCP tools. Do NOT accept the story or merge - commit your work and stop.\n\nIMPORTANT: Commit all your work before your process exits. The server will automatically run acceptance gates when your process exits.\n\nIf `script/test` still contains the generic 'No tests configured' stub, update it to run the project's actual test suite before starting implementation." +prompt = "You are working in a git worktree on story {{story_id}}. Read CLAUDE.md first, then .huskies/README.md to understand the dev process. Follow the workflow through implementation and verification. The worktree and feature branch already exist - do not create them. Check .mcp.json for MCP tools. Do NOT accept the story or merge - commit your work and stop.\n\nIMPORTANT: Commit all your work before your process exits. The server will automatically run acceptance gates when your process exits.\n\nIf `script/test` still contains the generic 'No tests configured' stub, update it to run the project's actual test suite before starting implementation." system_prompt = "You are a full-stack engineer working autonomously in a git worktree. Follow the Story-Driven Test Workflow strictly. Commit all your work before finishing. Do not accept stories, move them to archived, or merge to master." [[agent]] @@ -275,12 +275,12 @@ fn write_script_if_missing(path: &Path, content: &str) -> Result<(), String> { Ok(()) } -/// Write (or idempotently update) `.storkit/.gitignore` with Story Kit–specific -/// ignore patterns for files that live inside the `.storkit/` directory. -/// Patterns are relative to `.storkit/` as git resolves `.gitignore` files +/// Write (or idempotently update) `.huskies/.gitignore` with Story Kit–specific +/// ignore patterns for files that live inside the `.huskies/` directory. +/// Patterns are relative to `.huskies/` as git resolves `.gitignore` files /// relative to the directory that contains them. fn write_story_kit_gitignore(root: &Path) -> Result<(), String> { - // Entries that belong inside .storkit/.gitignore (relative to .storkit/). + // Entries that belong inside .huskies/.gitignore (relative to .huskies/). let entries = [ "bot.toml", "matrix_store/", @@ -299,10 +299,10 @@ fn write_story_kit_gitignore(root: &Path) -> Result<(), String> { "store.json", ]; - let gitignore_path = root.join(".storkit").join(".gitignore"); + let gitignore_path = root.join(".huskies").join(".gitignore"); let existing = if gitignore_path.exists() { fs::read_to_string(&gitignore_path) - .map_err(|e| format!("Failed to read .storkit/.gitignore: {}", e))? + .map_err(|e| format!("Failed to read .huskies/.gitignore: {}", e))? } else { String::new() }; @@ -327,19 +327,19 @@ fn write_story_kit_gitignore(root: &Path) -> Result<(), String> { } fs::write(&gitignore_path, new_content) - .map_err(|e| format!("Failed to write .storkit/.gitignore: {}", e))?; + .map_err(|e| format!("Failed to write .huskies/.gitignore: {}", e))?; Ok(()) } /// Append root-level Story Kit entries to the project `.gitignore`. -/// Only `.storkit_port` and `.mcp.json` remain here because they live at +/// Only `.huskies_port` and `.mcp.json` remain here because they live at /// the project root and git does not support `../` patterns in `.gitignore` -/// files, so they cannot be expressed in `.storkit/.gitignore`. -/// `store.json` is excluded via `.storkit/.gitignore` since it now lives -/// inside the `.storkit/` directory. +/// files, so they cannot be expressed in `.huskies/.gitignore`. +/// `store.json` is excluded via `.huskies/.gitignore` since it now lives +/// inside the `.huskies/` directory. fn append_root_gitignore_entries(root: &Path) -> Result<(), String> { - let entries = [".storkit_port", ".mcp.json"]; + let entries = [".huskies_port", ".mcp.json"]; let gitignore_path = root.join(".gitignore"); let existing = if gitignore_path.exists() { @@ -375,7 +375,7 @@ fn append_root_gitignore_entries(root: &Path) -> Result<(), String> { } pub(crate) fn scaffold_story_kit(root: &Path, port: u16) -> Result<(), String> { - let story_kit_root = root.join(".storkit"); + let story_kit_root = root.join(".huskies"); let specs_root = story_kit_root.join("specs"); let tech_root = specs_root.join("tech"); let functional_root = specs_root.join("functional"); @@ -433,7 +433,7 @@ pub(crate) fn scaffold_story_kit(root: &Path, port: u16) -> Result<(), String> { // Only written when missing — never overwrites an existing file, because // the port is environment-specific and must not clobber a running instance. let mcp_content = format!( - "{{\n \"mcpServers\": {{\n \"storkit\": {{\n \"type\": \"http\",\n \"url\": \"http://localhost:{port}/mcp\"\n }}\n }}\n}}\n" + "{{\n \"mcpServers\": {{\n \"huskies\": {{\n \"type\": \"http\",\n \"url\": \"http://localhost:{port}/mcp\"\n }}\n }}\n}}\n" ); write_file_if_missing(&root.join(".mcp.json"), &mcp_content)?; @@ -462,7 +462,7 @@ pub(crate) fn scaffold_story_kit(root: &Path, port: u16) -> Result<(), String> { let add_output = std::process::Command::new("git") .args([ "add", - ".storkit", + ".huskies", "script", ".gitignore", "CLAUDE.md", @@ -481,7 +481,7 @@ pub(crate) fn scaffold_story_kit(root: &Path, port: u16) -> Result<(), String> { let commit_output = std::process::Command::new("git") .args([ "-c", - "user.email=storkit@localhost", + "user.email=huskies@localhost", "-c", "user.name=Story Kit", "commit", @@ -514,12 +514,12 @@ mod tests { let dir = tempdir().unwrap(); scaffold_story_kit(dir.path(), 3001).unwrap(); - assert!(dir.path().join(".storkit/README.md").exists()); - assert!(dir.path().join(".storkit/project.toml").exists()); - assert!(dir.path().join(".storkit/specs/00_CONTEXT.md").exists()); - assert!(dir.path().join(".storkit/specs/tech/STACK.md").exists()); + assert!(dir.path().join(".huskies/README.md").exists()); + assert!(dir.path().join(".huskies/project.toml").exists()); + assert!(dir.path().join(".huskies/specs/00_CONTEXT.md").exists()); + assert!(dir.path().join(".huskies/specs/tech/STACK.md").exists()); // Old stories/ dirs should NOT be created - assert!(!dir.path().join(".storkit/stories").exists()); + assert!(!dir.path().join(".huskies/stories").exists()); assert!(dir.path().join("script/test").exists()); } @@ -537,7 +537,7 @@ mod tests { "6_archived", ]; for stage in &stages { - let path = dir.path().join(".storkit/work").join(stage); + let path = dir.path().join(".huskies/work").join(stage); assert!(path.is_dir(), "work/{} should be a directory", stage); assert!( path.join(".gitkeep").exists(), @@ -552,7 +552,7 @@ mod tests { let dir = tempdir().unwrap(); scaffold_story_kit(dir.path(), 3001).unwrap(); - let content = fs::read_to_string(dir.path().join(".storkit/project.toml")).unwrap(); + let content = fs::read_to_string(dir.path().join(".huskies/project.toml")).unwrap(); assert!(content.contains("[[agent]]")); assert!(content.contains("stage = \"coder\"")); assert!(content.contains("stage = \"qa\"")); @@ -565,8 +565,8 @@ mod tests { let dir = tempdir().unwrap(); scaffold_story_kit(dir.path(), 3001).unwrap(); - let content = fs::read_to_string(dir.path().join(".storkit/specs/00_CONTEXT.md")).unwrap(); - assert!(content.contains("")); + let content = fs::read_to_string(dir.path().join(".huskies/specs/00_CONTEXT.md")).unwrap(); + assert!(content.contains("")); assert!(content.contains("## High-Level Goal")); assert!(content.contains("## Core Features")); assert!(content.contains("## Domain Definition")); @@ -581,8 +581,8 @@ mod tests { let dir = tempdir().unwrap(); scaffold_story_kit(dir.path(), 3001).unwrap(); - let content = fs::read_to_string(dir.path().join(".storkit/specs/tech/STACK.md")).unwrap(); - assert!(content.contains("")); + let content = fs::read_to_string(dir.path().join(".huskies/specs/tech/STACK.md")).unwrap(); + assert!(content.contains("")); assert!(content.contains("## Core Stack")); assert!(content.contains("## Coding Standards")); assert!(content.contains("## Quality Gates")); @@ -612,7 +612,7 @@ mod tests { #[test] fn scaffold_story_kit_does_not_overwrite_existing() { let dir = tempdir().unwrap(); - let readme = dir.path().join(".storkit/README.md"); + let readme = dir.path().join(".huskies/README.md"); fs::create_dir_all(readme.parent().unwrap()).unwrap(); fs::write(&readme, "custom content").unwrap(); @@ -626,30 +626,30 @@ mod tests { let dir = tempdir().unwrap(); scaffold_story_kit(dir.path(), 3001).unwrap(); - let readme_content = fs::read_to_string(dir.path().join(".storkit/README.md")).unwrap(); - let toml_content = fs::read_to_string(dir.path().join(".storkit/project.toml")).unwrap(); + let readme_content = fs::read_to_string(dir.path().join(".huskies/README.md")).unwrap(); + let toml_content = fs::read_to_string(dir.path().join(".huskies/project.toml")).unwrap(); // Run again — must not change content or add duplicate .gitignore entries scaffold_story_kit(dir.path(), 3001).unwrap(); assert_eq!( - fs::read_to_string(dir.path().join(".storkit/README.md")).unwrap(), + fs::read_to_string(dir.path().join(".huskies/README.md")).unwrap(), readme_content ); assert_eq!( - fs::read_to_string(dir.path().join(".storkit/project.toml")).unwrap(), + fs::read_to_string(dir.path().join(".huskies/project.toml")).unwrap(), toml_content ); let story_kit_gitignore = - fs::read_to_string(dir.path().join(".storkit/.gitignore")).unwrap(); + fs::read_to_string(dir.path().join(".huskies/.gitignore")).unwrap(); let count = story_kit_gitignore .lines() .filter(|l| l.trim() == "worktrees/") .count(); assert_eq!( count, 1, - ".storkit/.gitignore should not have duplicate entries" + ".huskies/.gitignore should not have duplicate entries" ); } @@ -699,43 +699,43 @@ mod tests { let dir = tempdir().unwrap(); scaffold_story_kit(dir.path(), 3001).unwrap(); - // .storkit/.gitignore must contain relative patterns for files under .storkit/ - let sk_content = fs::read_to_string(dir.path().join(".storkit/.gitignore")).unwrap(); + // .huskies/.gitignore must contain relative patterns for files under .huskies/ + let sk_content = fs::read_to_string(dir.path().join(".huskies/.gitignore")).unwrap(); assert!(sk_content.contains("worktrees/")); assert!(sk_content.contains("merge_workspace/")); assert!(sk_content.contains("coverage/")); assert!(sk_content.contains("matrix_history.json")); assert!(sk_content.contains("timers.json")); - // Must NOT contain absolute .storkit/ prefixed paths - assert!(!sk_content.contains(".storkit/")); + // Must NOT contain absolute .huskies/ prefixed paths + assert!(!sk_content.contains(".huskies/")); - // Root .gitignore must contain root-level storkit entries + // Root .gitignore must contain root-level huskies entries let root_content = fs::read_to_string(dir.path().join(".gitignore")).unwrap(); - assert!(root_content.contains(".storkit_port")); - // store.json now lives inside .storkit/ and must NOT appear in root .gitignore + assert!(root_content.contains(".huskies_port")); + // store.json now lives inside .huskies/ and must NOT appear in root .gitignore assert!(!root_content.contains("store.json")); - // Root .gitignore must NOT contain .storkit/ sub-directory patterns - assert!(!root_content.contains(".storkit/worktrees/")); - assert!(!root_content.contains(".storkit/merge_workspace/")); - assert!(!root_content.contains(".storkit/coverage/")); - // store.json must be in .storkit/.gitignore instead + // Root .gitignore must NOT contain .huskies/ sub-directory patterns + assert!(!root_content.contains(".huskies/worktrees/")); + assert!(!root_content.contains(".huskies/merge_workspace/")); + assert!(!root_content.contains(".huskies/coverage/")); + // store.json must be in .huskies/.gitignore instead assert!(sk_content.contains("store.json")); } #[test] fn scaffold_story_kit_gitignore_does_not_duplicate_existing_entries() { let dir = tempdir().unwrap(); - // Pre-create .storkit dir and .gitignore with some entries already present - fs::create_dir_all(dir.path().join(".storkit")).unwrap(); + // Pre-create .huskies dir and .gitignore with some entries already present + fs::create_dir_all(dir.path().join(".huskies")).unwrap(); fs::write( - dir.path().join(".storkit/.gitignore"), + dir.path().join(".huskies/.gitignore"), "worktrees/\ncoverage/\n", ) .unwrap(); scaffold_story_kit(dir.path(), 3001).unwrap(); - let content = fs::read_to_string(dir.path().join(".storkit/.gitignore")).unwrap(); + let content = fs::read_to_string(dir.path().join(".huskies/.gitignore")).unwrap(); let worktrees_count = content.lines().filter(|l| l.trim() == "worktrees/").count(); assert_eq!(worktrees_count, 1, "worktrees/ should not be duplicated"); let coverage_count = content.lines().filter(|l| l.trim() == "coverage/").count(); @@ -759,12 +759,12 @@ mod tests { let content = fs::read_to_string(&claude_md).unwrap(); assert!( - content.contains(""), + content.contains(""), "CLAUDE.md should contain the scaffold sentinel" ); assert!( - content.contains("Read .storkit/README.md"), - "CLAUDE.md should include directive to read .storkit/README.md" + content.contains("Read .huskies/README.md"), + "CLAUDE.md should include directive to read .huskies/README.md" ); assert!( content.contains("Never chain shell commands"), @@ -801,7 +801,7 @@ mod tests { let content = fs::read_to_string(&mcp_path).unwrap(); assert!(content.contains("4242"), ".mcp.json should reference the given port"); assert!(content.contains("localhost"), ".mcp.json should reference localhost"); - assert!(content.contains("storkit"), ".mcp.json should name the storkit server"); + assert!(content.contains("huskies"), ".mcp.json should name the huskies server"); } #[test] @@ -1149,7 +1149,7 @@ mod tests { scaffold_story_kit(dir.path(), 3001).unwrap(); - let content = fs::read_to_string(dir.path().join(".storkit/project.toml")).unwrap(); + let content = fs::read_to_string(dir.path().join(".huskies/project.toml")).unwrap(); assert!( content.contains("[[component]]"), "project.toml should contain a component entry" @@ -1169,7 +1169,7 @@ mod tests { let dir = tempdir().unwrap(); scaffold_story_kit(dir.path(), 3001).unwrap(); - let content = fs::read_to_string(dir.path().join(".storkit/project.toml")).unwrap(); + let content = fs::read_to_string(dir.path().join(".huskies/project.toml")).unwrap(); assert!( content.contains("[[component]]"), "project.toml should always have at least one component" @@ -1188,7 +1188,7 @@ mod tests { #[test] fn scaffold_does_not_overwrite_existing_project_toml_with_components() { let dir = tempdir().unwrap(); - let sk_dir = dir.path().join(".storkit"); + let sk_dir = dir.path().join(".huskies"); fs::create_dir_all(&sk_dir).unwrap(); let existing = "[[component]]\nname = \"custom\"\npath = \".\"\nsetup = [\"make build\"]\n"; fs::write(sk_dir.join("project.toml"), existing).unwrap(); diff --git a/server/src/io/onboarding.rs b/server/src/io/onboarding.rs index 8e0e435a..071ec2d7 100644 --- a/server/src/io/onboarding.rs +++ b/server/src/io/onboarding.rs @@ -4,7 +4,7 @@ use std::path::Path; /// Only untouched templates contain this marker — real project content /// will never include it, so it avoids false positives when the project /// itself is an "Agentic AI Code Assistant". -const TEMPLATE_SENTINEL: &str = ""; +const TEMPLATE_SENTINEL: &str = ""; /// Marker found in the default `script/test` scaffold output. const TEMPLATE_MARKER_SCRIPT: &str = "No tests configured"; @@ -18,7 +18,7 @@ pub struct OnboardingStatus { pub needs_stack: bool, /// True when `script/test` still contains the scaffold placeholder. pub needs_test_script: bool, - /// True when `.storkit/project.toml` is missing or has no + /// True when `.huskies/project.toml` is missing or has no /// `[[component]]` entries. pub needs_project_toml: bool, } @@ -33,7 +33,7 @@ impl OnboardingStatus { /// Inspect the project at `project_root` and determine which onboarding /// steps are still required. pub fn check_onboarding_status(project_root: &Path) -> OnboardingStatus { - let story_kit = project_root.join(".storkit"); + let story_kit = project_root.join(".huskies"); OnboardingStatus { needs_context: is_template_or_missing( @@ -99,13 +99,13 @@ mod tests { // Write content that includes the scaffold sentinel fs::write( - root.join(".storkit/specs/00_CONTEXT.md"), - "\n# Project Context\nPlaceholder...", + root.join(".huskies/specs/00_CONTEXT.md"), + "\n# Project Context\nPlaceholder...", ) .unwrap(); fs::write( - root.join(".storkit/specs/tech/STACK.md"), - "\n# Tech Stack\nPlaceholder...", + root.join(".huskies/specs/tech/STACK.md"), + "\n# Tech Stack\nPlaceholder...", ) .unwrap(); @@ -123,12 +123,12 @@ mod tests { // Real project content that happens to mention "Agentic AI Code Assistant" // but does NOT contain the scaffold sentinel — should NOT trigger onboarding. fs::write( - root.join(".storkit/specs/00_CONTEXT.md"), + root.join(".huskies/specs/00_CONTEXT.md"), "# Project Context\nTo build a standalone Agentic AI Code Assistant application.", ) .unwrap(); fs::write( - root.join(".storkit/specs/tech/STACK.md"), + root.join(".huskies/specs/tech/STACK.md"), "# Tech Stack\nThis is an Agentic Code Assistant binary.", ) .unwrap(); @@ -145,12 +145,12 @@ mod tests { let root = setup_project(&dir); fs::write( - root.join(".storkit/specs/00_CONTEXT.md"), + root.join(".huskies/specs/00_CONTEXT.md"), "# My Project\n\nThis is an e-commerce platform for selling widgets.", ) .unwrap(); fs::write( - root.join(".storkit/specs/tech/STACK.md"), + root.join(".huskies/specs/tech/STACK.md"), "# Tech Stack\n\n## Backend: Python + FastAPI\n## Frontend: React + TypeScript", ) .unwrap(); @@ -166,8 +166,8 @@ mod tests { let dir = TempDir::new().unwrap(); let root = setup_project(&dir); - fs::write(root.join(".storkit/specs/00_CONTEXT.md"), " \n").unwrap(); - fs::write(root.join(".storkit/specs/tech/STACK.md"), "").unwrap(); + fs::write(root.join(".huskies/specs/00_CONTEXT.md"), " \n").unwrap(); + fs::write(root.join(".huskies/specs/tech/STACK.md"), "").unwrap(); let status = check_onboarding_status(&root); assert!(status.needs_context); @@ -222,7 +222,7 @@ mod tests { let dir = TempDir::new().unwrap(); let root = setup_project(&dir); - fs::write(root.join(".storkit/project.toml"), "# empty config\n").unwrap(); + fs::write(root.join(".huskies/project.toml"), "# empty config\n").unwrap(); let status = check_onboarding_status(&root); assert!(status.needs_project_toml); @@ -234,7 +234,7 @@ mod tests { let root = setup_project(&dir); fs::write( - root.join(".storkit/project.toml"), + root.join(".huskies/project.toml"), "[[component]]\nname = \"app\"\npath = \".\"\nsetup = [\"cargo check\"]\n", ) .unwrap(); @@ -252,12 +252,12 @@ mod tests { // Write real content for the required onboarding files fs::write( - root.join(".storkit/specs/00_CONTEXT.md"), + root.join(".huskies/specs/00_CONTEXT.md"), "# My Project\n\nReal project context.", ) .unwrap(); fs::write( - root.join(".storkit/specs/tech/STACK.md"), + root.join(".huskies/specs/tech/STACK.md"), "# My Stack\n\nReal stack content.", ) .unwrap(); @@ -289,13 +289,13 @@ mod tests { // Context still has sentinel fs::write( - root.join(".storkit/specs/00_CONTEXT.md"), - "\n# Project Context\nPlaceholder...", + root.join(".huskies/specs/00_CONTEXT.md"), + "\n# Project Context\nPlaceholder...", ) .unwrap(); // Stack is customised (no sentinel) fs::write( - root.join(".storkit/specs/tech/STACK.md"), + root.join(".huskies/specs/tech/STACK.md"), "# My Stack\nRuby on Rails + PostgreSQL", ) .unwrap(); diff --git a/server/src/io/test_helpers.rs b/server/src/io/test_helpers.rs index 8c815cbe..0b483634 100644 --- a/server/src/io/test_helpers.rs +++ b/server/src/io/test_helpers.rs @@ -6,13 +6,13 @@ use std::fs; use std::path::PathBuf; use tempfile::TempDir; -/// Create a minimal storkit project directory structure under `dir`. +/// Create a minimal huskies project directory structure under `dir`. /// -/// Creates `.storkit/specs/tech/` and `script/`, then returns the root path. +/// Creates `.huskies/specs/tech/` and `script/`, then returns the root path. /// Used by onboarding and wizard tests. pub(crate) fn setup_project(dir: &TempDir) -> PathBuf { let root = dir.path().to_path_buf(); - let sk = root.join(".storkit"); + let sk = root.join(".huskies"); fs::create_dir_all(sk.join("specs").join("tech")).unwrap(); fs::create_dir_all(root.join("script")).unwrap(); root diff --git a/server/src/io/watcher.rs b/server/src/io/watcher.rs index 9104da0f..4d1d528d 100644 --- a/server/src/io/watcher.rs +++ b/server/src/io/watcher.rs @@ -1,10 +1,10 @@ -//! Filesystem watcher for `.storkit/work/` and `.storkit/project.toml`. +//! Filesystem watcher for `.huskies/work/` and `.huskies/project.toml`. //! //! Watches the work pipeline directories for file changes, infers the lifecycle //! stage from the target directory name, auto-commits with a deterministic message, //! and broadcasts a [`WatcherEvent`] to all connected WebSocket clients. //! -//! Also watches `.storkit/project.toml` for modifications and broadcasts +//! Also watches `.huskies/project.toml` for modifications and broadcasts //! [`WatcherEvent::ConfigChanged`] so the frontend can reload the agent roster //! without a server restart. //! @@ -48,7 +48,7 @@ pub enum WatcherEvent { /// `None` for creations, deletions, or synthetic events. from_stage: Option, }, - /// `.storkit/project.toml` was modified at the project root (not inside a worktree). + /// `.huskies/project.toml` was modified at the project root (not inside a worktree). ConfigChanged, /// An agent's state changed (started, stopped, completed, etc.). /// Triggers a pipeline state refresh so the frontend can update agent @@ -90,8 +90,8 @@ pub enum WatcherEvent { }, } -/// Return `true` if `path` is the root-level `.storkit/project.toml`, i.e. -/// `{git_root}/.storkit/project.toml`. +/// Return `true` if `path` is the root-level `.huskies/project.toml`, i.e. +/// `{git_root}/.huskies/project.toml`. /// /// Returns `false` for paths inside worktree directories (paths containing /// a `worktrees` component). @@ -100,19 +100,19 @@ pub fn is_config_file(path: &Path, git_root: &Path) -> bool { if path.components().any(|c| c.as_os_str() == "worktrees") { return false; } - let expected = git_root.join(".storkit").join("project.toml"); + let expected = git_root.join(".huskies").join("project.toml"); path == expected } /// Map a pipeline directory name to a (action, commit-message-prefix) pair. fn stage_metadata(stage: &str, item_id: &str) -> Option<(&'static str, String)> { let (action, prefix) = match stage { - "1_backlog" => ("create", format!("storkit: create {item_id}")), - "2_current" => ("start", format!("storkit: start {item_id}")), - "3_qa" => ("qa", format!("storkit: queue {item_id} for QA")), - "4_merge" => ("merge", format!("storkit: queue {item_id} for merge")), - "5_done" => ("done", format!("storkit: done {item_id}")), - "6_archived" => ("accept", format!("storkit: accept {item_id}")), + "1_backlog" => ("create", format!("huskies: create {item_id}")), + "2_current" => ("start", format!("huskies: start {item_id}")), + "3_qa" => ("qa", format!("huskies: queue {item_id} for QA")), + "4_merge" => ("merge", format!("huskies: queue {item_id} for merge")), + "5_done" => ("done", format!("huskies: done {item_id}")), + "6_archived" => ("accept", format!("huskies: accept {item_id}")), _ => return None, }; Some((action, prefix)) @@ -121,7 +121,7 @@ fn stage_metadata(stage: &str, item_id: &str) -> Option<(&'static str, String)> /// Return the pipeline stage name for a path if it is a `.md` file living /// directly inside one of the known work subdirectories, otherwise `None`. /// -/// Explicitly returns `None` for any path under `.storkit/worktrees/` so +/// Explicitly returns `None` for any path under `.huskies/worktrees/` so /// that code changes made by agents in their isolated worktrees are never /// auto-committed to master by the watcher. fn stage_for_path(path: &Path) -> Option { @@ -146,11 +146,11 @@ fn stage_for_path(path: &Path) -> Option { /// Stage all changes in the work directory and commit with the given message. /// -/// Uses `git add -A .storkit/work/` to catch both additions and deletions in +/// Uses `git add -A .huskies/work/` to catch both additions and deletions in /// a single commit. Returns `Ok(true)` if a commit was made, `Ok(false)` if /// there was nothing to commit, and `Err` for unexpected failures. fn git_add_work_and_commit(git_root: &Path, message: &str) -> Result { - let work_rel = PathBuf::from(".storkit").join("work"); + let work_rel = PathBuf::from(".huskies").join("work"); let add_out = std::process::Command::new("git") .args(["add", "-A"]) @@ -199,7 +199,7 @@ fn should_commit_stage(stage: &str) -> bool { /// /// Only files that still exist on disk are used to derive the commit message /// (they represent the destination of a move or a new file). Deletions are -/// captured by `git add -A .storkit/work/` automatically. +/// captured by `git add -A .huskies/work/` automatically. /// /// Only terminal stages (`1_backlog` and `6_archived`) trigger git commits. /// All stages broadcast a [`WatcherEvent`] so the frontend stays in sync. @@ -240,7 +240,7 @@ fn flush_pending( ( "remove", item.to_string(), - format!("storkit: remove {item}"), + format!("huskies: remove {item}"), ) }; @@ -392,9 +392,9 @@ fn sweep_done_to_archived(work_dir: &Path, git_root: &Path, done_retention: Dura /// Start the filesystem watcher on a dedicated OS thread. /// -/// `work_dir` — absolute path to `.storkit/work/` (watched recursively). +/// `work_dir` — absolute path to `.huskies/work/` (watched recursively). /// `git_root` — project root (passed to `git` commands as cwd, and used to -/// derive the config file path `.storkit/project.toml`). +/// derive the config file path `.huskies/project.toml`). /// `event_tx` — broadcast sender; each connected WebSocket client holds a receiver. /// `watcher_config` — initial sweep configuration loaded from `project.toml`. pub fn start_watcher( @@ -421,8 +421,8 @@ pub fn start_watcher( return; } - // Also watch .storkit/project.toml for hot-reload of agent config. - let config_file = git_root.join(".storkit").join("project.toml"); + // Also watch .huskies/project.toml for hot-reload of agent config. + let config_file = git_root.join(".huskies").join("project.toml"); if config_file.exists() && let Err(e) = watcher.watch(&config_file, RecursiveMode::NonRecursive) { @@ -575,9 +575,9 @@ mod tests { .expect("git initial commit"); } - /// Create the `.storkit/work/{stage}/` dir tree inside `root`. + /// Create the `.huskies/work/{stage}/` dir tree inside `root`. fn make_stage_dir(root: &std::path::Path, stage: &str) -> PathBuf { - let dir = root.join(".storkit").join("work").join(stage); + let dir = root.join(".huskies").join("work").join(stage); fs::create_dir_all(&dir).expect("create stage dir"); dir } @@ -591,7 +591,7 @@ mod tests { let stage_dir = make_stage_dir(tmp.path(), "2_current"); fs::write(stage_dir.join("42_story_foo.md"), "---\nname: test\n---\n").unwrap(); - let result = git_add_work_and_commit(tmp.path(), "storkit: start 42_story_foo"); + let result = git_add_work_and_commit(tmp.path(), "huskies: start 42_story_foo"); assert_eq!( result, Ok(true), @@ -607,10 +607,10 @@ mod tests { fs::write(stage_dir.join("42_story_foo.md"), "---\nname: test\n---\n").unwrap(); // First commit — should succeed. - git_add_work_and_commit(tmp.path(), "storkit: start 42_story_foo").unwrap(); + git_add_work_and_commit(tmp.path(), "huskies: start 42_story_foo").unwrap(); // Second call with no changes — should return Ok(false). - let result = git_add_work_and_commit(tmp.path(), "storkit: start 42_story_foo"); + let result = git_add_work_and_commit(tmp.path(), "huskies: start 42_story_foo"); assert_eq!( result, Ok(false), @@ -646,7 +646,7 @@ mod tests { assert_eq!(stage, "1_backlog"); assert_eq!(item_id, "42_story_foo"); assert_eq!(action, "create"); - assert_eq!(commit_msg, "storkit: create 42_story_foo"); + assert_eq!(commit_msg, "huskies: create 42_story_foo"); } other => panic!("unexpected event: {other:?}"), } @@ -659,7 +659,7 @@ mod tests { .expect("git log"); let log_msg = String::from_utf8_lossy(&log.stdout); assert!( - log_msg.contains("storkit: create 42_story_foo"), + log_msg.contains("huskies: create 42_story_foo"), "terminal stage should produce a git commit" ); } @@ -691,7 +691,7 @@ mod tests { assert_eq!(stage, "2_current"); assert_eq!(item_id, "42_story_foo"); assert_eq!(action, "start"); - assert_eq!(commit_msg, "storkit: start 42_story_foo"); + assert_eq!(commit_msg, "huskies: start 42_story_foo"); } other => panic!("unexpected event: {other:?}"), } @@ -704,7 +704,7 @@ mod tests { .expect("git log"); let log_msg = String::from_utf8_lossy(&log.stdout); assert!( - !log_msg.contains("storkit:"), + !log_msg.contains("huskies:"), "intermediate stage should NOT produce a git commit" ); } @@ -712,11 +712,11 @@ mod tests { #[test] fn flush_pending_broadcasts_for_all_pipeline_stages() { let stages = [ - ("1_backlog", "create", "storkit: create 10_story_x"), - ("3_qa", "qa", "storkit: queue 10_story_x for QA"), - ("4_merge", "merge", "storkit: queue 10_story_x for merge"), - ("5_done", "done", "storkit: done 10_story_x"), - ("6_archived", "accept", "storkit: accept 10_story_x"), + ("1_backlog", "create", "huskies: create 10_story_x"), + ("3_qa", "qa", "huskies: queue 10_story_x for QA"), + ("4_merge", "merge", "huskies: queue 10_story_x for merge"), + ("5_done", "done", "huskies: done 10_story_x"), + ("6_archived", "accept", "huskies: accept 10_story_x"), ]; for (stage, expected_action, expected_msg) in stages { @@ -754,7 +754,7 @@ mod tests { make_stage_dir(tmp.path(), "2_current"); let deleted_path = tmp .path() - .join(".storkit") + .join(".huskies") .join("work") .join("2_current") .join("42_story_foo.md"); @@ -785,7 +785,7 @@ mod tests { let tmp = TempDir::new().unwrap(); init_git_repo(tmp.path()); // File sits in an unrecognised directory. - let unknown_dir = tmp.path().join(".storkit").join("work").join("9_unknown"); + let unknown_dir = tmp.path().join(".huskies").join("work").join("9_unknown"); fs::create_dir_all(&unknown_dir).unwrap(); let path = unknown_dir.join("42_story_foo.md"); fs::write(&path, "---\nname: test\n---\n").unwrap(); @@ -961,7 +961,7 @@ mod tests { make_stage_dir(tmp.path(), "3_qa"); let qa_path = tmp .path() - .join(".storkit") + .join(".huskies") .join("work") .join("3_qa") .join("42_story_foo.md"); @@ -1015,7 +1015,7 @@ mod tests { #[test] fn stage_for_path_recognises_pipeline_dirs() { - let base = PathBuf::from("/proj/.storkit/work"); + let base = PathBuf::from("/proj/.huskies/work"); assert_eq!( stage_for_path(&base.join("2_current/42_story_foo.md")), Some("2_current".to_string()) @@ -1037,7 +1037,7 @@ mod tests { #[test] fn stage_for_path_ignores_worktree_paths() { - let worktrees = PathBuf::from("/proj/.storkit/worktrees"); + let worktrees = PathBuf::from("/proj/.huskies/worktrees"); // Code changes inside a worktree must be ignored. assert_eq!( @@ -1048,7 +1048,7 @@ mod tests { // Even if a worktree happens to contain a path component that looks // like a pipeline stage, it must still be ignored. assert_eq!( - stage_for_path(&worktrees.join("42_story_foo/.storkit/work/2_current/42_story_foo.md")), + stage_for_path(&worktrees.join("42_story_foo/.huskies/work/2_current/42_story_foo.md")), None, ); @@ -1056,7 +1056,7 @@ mod tests { // segment (not an exact component) must NOT be filtered out. assert_eq!( stage_for_path(&PathBuf::from( - "/proj/.storkit/work/2_current/not_worktrees_story.md" + "/proj/.huskies/work/2_current/not_worktrees_story.md" )), Some("2_current".to_string()), ); @@ -1080,15 +1080,15 @@ mod tests { fn stage_metadata_returns_correct_actions() { let (action, msg) = stage_metadata("2_current", "42_story_foo").unwrap(); assert_eq!(action, "start"); - assert_eq!(msg, "storkit: start 42_story_foo"); + assert_eq!(msg, "huskies: start 42_story_foo"); let (action, msg) = stage_metadata("5_done", "42_story_foo").unwrap(); assert_eq!(action, "done"); - assert_eq!(msg, "storkit: done 42_story_foo"); + assert_eq!(msg, "huskies: done 42_story_foo"); let (action, msg) = stage_metadata("6_archived", "42_story_foo").unwrap(); assert_eq!(action, "accept"); - assert_eq!(msg, "storkit: accept 42_story_foo"); + assert_eq!(msg, "huskies: accept 42_story_foo"); assert!(stage_metadata("unknown", "id").is_none()); } @@ -1096,7 +1096,7 @@ mod tests { #[test] fn is_config_file_identifies_root_project_toml() { let git_root = PathBuf::from("/proj"); - let config = git_root.join(".storkit").join("project.toml"); + let config = git_root.join(".huskies").join("project.toml"); assert!(is_config_file(&config, &git_root)); } @@ -1105,7 +1105,7 @@ mod tests { let git_root = PathBuf::from("/proj"); // project.toml inside a worktree must NOT be treated as the root config. let worktree_config = - PathBuf::from("/proj/.storkit/worktrees/42_story_foo/.storkit/project.toml"); + PathBuf::from("/proj/.huskies/worktrees/42_story_foo/.huskies/project.toml"); assert!(!is_config_file(&worktree_config, &git_root)); } @@ -1114,11 +1114,11 @@ mod tests { let git_root = PathBuf::from("/proj"); // Random files must not match. assert!(!is_config_file( - &PathBuf::from("/proj/.storkit/work/2_current/42_story_foo.md"), + &PathBuf::from("/proj/.huskies/work/2_current/42_story_foo.md"), &git_root )); assert!(!is_config_file( - &PathBuf::from("/proj/.storkit/README.md"), + &PathBuf::from("/proj/.huskies/README.md"), &git_root )); } @@ -1126,7 +1126,7 @@ mod tests { #[test] fn is_config_file_rejects_wrong_root() { let git_root = PathBuf::from("/proj"); - let other_root_config = PathBuf::from("/other/.storkit/project.toml"); + let other_root_config = PathBuf::from("/other/.huskies/project.toml"); assert!(!is_config_file(&other_root_config, &git_root)); } @@ -1135,7 +1135,7 @@ mod tests { #[test] fn sweep_moves_old_items_to_archived() { let tmp = TempDir::new().unwrap(); - let work_dir = tmp.path().join(".storkit").join("work"); + let work_dir = tmp.path().join(".huskies").join("work"); let done_dir = work_dir.join("5_done"); let archived_dir = work_dir.join("6_archived"); fs::create_dir_all(&done_dir).unwrap(); @@ -1165,7 +1165,7 @@ mod tests { #[test] fn sweep_keeps_recent_items_in_done() { let tmp = TempDir::new().unwrap(); - let work_dir = tmp.path().join(".storkit").join("work"); + let work_dir = tmp.path().join(".huskies").join("work"); let done_dir = work_dir.join("5_done"); fs::create_dir_all(&done_dir).unwrap(); @@ -1182,7 +1182,7 @@ mod tests { #[test] fn sweep_respects_custom_retention() { let tmp = TempDir::new().unwrap(); - let work_dir = tmp.path().join(".storkit").join("work"); + let work_dir = tmp.path().join(".huskies").join("work"); let done_dir = work_dir.join("5_done"); let archived_dir = work_dir.join("6_archived"); fs::create_dir_all(&done_dir).unwrap(); @@ -1211,7 +1211,7 @@ mod tests { #[test] fn sweep_custom_retention_keeps_younger_items() { let tmp = TempDir::new().unwrap(); - let work_dir = tmp.path().join(".storkit").join("work"); + let work_dir = tmp.path().join(".huskies").join("work"); let done_dir = work_dir.join("5_done"); fs::create_dir_all(&done_dir).unwrap(); @@ -1255,7 +1255,7 @@ mod tests { let git_root = tmp.path().to_path_buf(); init_git_repo(&git_root); - let work_dir = git_root.join(".storkit").join("work"); + let work_dir = git_root.join(".huskies").join("work"); let done_dir = work_dir.join("5_done"); fs::create_dir_all(&done_dir).unwrap(); @@ -1298,7 +1298,7 @@ mod tests { let git_root = tmp.path().to_path_buf(); init_git_repo(&git_root); - let work_dir = git_root.join(".storkit").join("work"); + let work_dir = git_root.join(".huskies").join("work"); let archived_dir = work_dir.join("6_archived"); fs::create_dir_all(&archived_dir).unwrap(); @@ -1339,7 +1339,7 @@ mod tests { let git_root = tmp.path().to_path_buf(); init_git_repo(&git_root); - let work_dir = git_root.join(".storkit").join("work"); + let work_dir = git_root.join(".huskies").join("work"); let done_dir = work_dir.join("5_done"); fs::create_dir_all(&done_dir).unwrap(); diff --git a/server/src/io/wizard.rs b/server/src/io/wizard.rs index 7d64fccd..2f0a0c95 100644 --- a/server/src/io/wizard.rs +++ b/server/src/io/wizard.rs @@ -7,7 +7,7 @@ use std::path::Path; #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum WizardStep { - /// Step 1: scaffold .storkit/ directory structure and project.toml + /// Step 1: scaffold .huskies/ directory structure and project.toml Scaffold, /// Step 2: generate specs/00_CONTEXT.md Context, @@ -76,7 +76,7 @@ pub struct StepState { pub content: Option, } -/// Persistent wizard state, stored in `.storkit/wizard_state.json`. +/// Persistent wizard state, stored in `.huskies/wizard_state.json`. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct WizardState { pub steps: Vec, @@ -103,7 +103,7 @@ impl Default for WizardState { impl WizardState { /// Path to the wizard state file relative to the project root. fn state_path(project_root: &Path) -> std::path::PathBuf { - project_root.join(".storkit").join("wizard_state.json") + project_root.join(".huskies").join("wizard_state.json") } /// Load wizard state from disk, or return None if it doesn't exist. @@ -122,7 +122,7 @@ impl WizardState { } /// Create wizard state file if it doesn't already exist. - /// Step 1 (Scaffold) is automatically confirmed since `storkit init` + /// Step 1 (Scaffold) is automatically confirmed since `huskies init` /// has already run the scaffold. pub fn init_if_missing(project_root: &Path) { if Self::load(project_root).is_some() { diff --git a/server/src/llm/prompts.rs b/server/src/llm/prompts.rs index b63b3ee8..ccaa62d8 100644 --- a/server/src/llm/prompts.rs +++ b/server/src/llm/prompts.rs @@ -18,7 +18,7 @@ You have the following tools available: YOUR WORKFLOW: When the user requests a feature or change: -1. **Understand:** Read `.storkit/README.md` if you haven't already to understand the development process +1. **Understand:** Read `.huskies/README.md` if you haven't already to understand the development process 2. **Explore:** Use `read_file` and `list_directory` to understand the current codebase structure 3. **Implement:** Use `write_file` to create or modify files directly 4. **Verify:** Use `exec_shell` to run tests, linters, or build commands to verify your changes work @@ -100,7 +100,7 @@ Ask the user: - Who are the target users? - What are the core features or goals? -Then use `write_file` to write `.storkit/specs/00_CONTEXT.md` with: +Then use `write_file` to write `.huskies/specs/00_CONTEXT.md` with: - **High-Level Goal** — a clear, concise summary of what the project does - **Core Features** — 3-5 bullet points - **Domain Definition** — key terms and roles @@ -114,7 +114,7 @@ Ask the user: - What test runner(s)? (e.g. cargo test, pytest, jest, pnpm test) - What linter(s)? (e.g. clippy, eslint, biome, ruff) -Then use `write_file` to write `.storkit/specs/tech/STACK.md` with: +Then use `write_file` to write `.huskies/specs/tech/STACK.md` with: - **Overview** of the architecture - **Core Stack** — languages, frameworks, build tools - **Coding Standards** — formatting, linting, quality gates @@ -131,7 +131,7 @@ Based on the tech stack answers, use `write_file` to write `script/test` — a b The script must start with `#!/usr/bin/env bash` and `set -euo pipefail`. ## Step 4: Project Configuration -The scaffold has written `.storkit/project.toml` with example `[[component]]` sections. You must replace these examples with real definitions that match the project's actual tech stack. +The scaffold has written `.huskies/project.toml` with example `[[component]]` sections. You must replace these examples with real definitions that match the project's actual tech stack. First, inspect the project structure to identify the tech stack: - Use `list_directory(".")` to see top-level files and directories @@ -139,9 +139,9 @@ First, inspect the project structure to identify the tech stack: - Check subdirectories like `frontend/`, `backend/`, `app/`, `web/` for nested stacks - If you find a `package.json`, check whether `pnpm-lock.yaml`, `yarn.lock`, or `package-lock.json` exists to determine the package manager -Then use `read_file(".storkit/project.toml")` to see the current content, keeping the `[[agent]]` sections intact. +Then use `read_file(".huskies/project.toml")` to see the current content, keeping the `[[agent]]` sections intact. -Finally, use `write_file` to rewrite `.storkit/project.toml` with real `[[component]]` entries. Each component needs: +Finally, use `write_file` to rewrite `.huskies/project.toml` with real `[[component]]` entries. Each component needs: - `name` — component identifier (e.g. "backend", "frontend", "app") - `path` — relative path from project root (use "." for root, "frontend" for a frontend subdirectory) - `setup` — list of setup commands that install dependencies and verify the build (e.g. ["pnpm install"], ["cargo check"]) diff --git a/server/src/llm/providers/claude_code.rs b/server/src/llm/providers/claude_code.rs index 6bcdb277..bb2b8615 100644 --- a/server/src/llm/providers/claude_code.rs +++ b/server/src/llm/providers/claude_code.rs @@ -216,10 +216,10 @@ fn run_pty_session( // are emitted and tool-start activity signals never fire. cmd.arg("--include-partial-messages"); // Delegate permission decisions to the MCP prompt_permission tool. - // Claude Code will call this tool via the storkit MCP server when + // Claude Code will call this tool via the huskies MCP server when // a tool requires user approval, instead of using PTY stdin/stdout. cmd.arg("--permission-prompt-tool"); - cmd.arg("mcp__storkit__prompt_permission"); + cmd.arg("mcp__huskies__prompt_permission"); // Note: --system is not a valid Claude Code CLI flag. System-level // instructions (like bot name) are prepended to the user prompt instead. cmd.cwd(cwd); @@ -229,7 +229,7 @@ fn run_pty_session( cmd.env("CLAUDECODE", ""); slog!( - "[pty-debug] Spawning: claude -p \"{}\" {} --output-format stream-json --verbose --include-partial-messages --permission-prompt-tool mcp__storkit__prompt_permission", + "[pty-debug] Spawning: claude -p \"{}\" {} --output-format stream-json --verbose --include-partial-messages --permission-prompt-tool mcp__huskies__prompt_permission", user_message, resume_session_id .map(|s| format!("--resume {s}")) diff --git a/server/src/main.rs b/server/src/main.rs index d2244bbd..68bdb760 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -57,7 +57,7 @@ fn parse_cli_args(args: &[String]) -> Result { std::process::exit(0); } "--version" | "-V" => { - println!("storkit {}", env!("CARGO_PKG_VERSION")); + println!("huskies {}", env!("CARGO_PKG_VERSION")); std::process::exit(0); } "--port" => { @@ -97,18 +97,18 @@ fn parse_cli_args(args: &[String]) -> Result { } fn print_help() { - println!("storkit [OPTIONS] [PATH]"); - println!("storkit init [OPTIONS] [PATH]"); + println!("huskies [OPTIONS] [PATH]"); + println!("huskies init [OPTIONS] [PATH]"); println!(); - println!("Serve a storkit project."); + println!("Serve a huskies project."); println!(); println!("COMMANDS:"); - println!(" init Scaffold a new .storkit/ project and start the interactive setup wizard."); + println!(" init Scaffold a new .huskies/ project and start the interactive setup wizard."); println!(); println!("ARGS:"); println!( " PATH Path to an existing project directory. \ - If omitted, storkit searches parent directories for a .storkit/ root." + If omitted, huskies searches parent directories for a .huskies/ root." ); println!(); println!("OPTIONS:"); @@ -139,10 +139,10 @@ async fn main() -> Result<(), std::io::Error> { let app_state = Arc::new(SessionState::default()); let cwd = std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")); - // Migrate legacy root-level store.json into .storkit/ if the new path does + // Migrate legacy root-level store.json into .huskies/ if the new path does // not yet exist. This keeps existing deployments working after upgrade. let legacy_store_path = cwd.join("store.json"); - let store_path = cwd.join(".storkit").join("store.json"); + let store_path = cwd.join(".huskies").join("store.json"); if legacy_store_path.exists() && !store_path.exists() { if let Some(parent) = store_path.parent() { let _ = std::fs::create_dir_all(parent); @@ -160,7 +160,7 @@ async fn main() -> Result<(), std::io::Error> { Ok(args) => args, Err(msg) => { eprintln!("error: {msg}"); - eprintln!("Run 'storkit --help' for usage."); + eprintln!("Run 'huskies --help' for usage."); std::process::exit(1); } }; @@ -187,7 +187,7 @@ async fn main() -> Result<(), std::io::Error> { } if is_init { - // `storkit init [PATH]` — always scaffold, never search parents. + // `huskies init [PATH]` — always scaffold, never search parents. let init_root = explicit_path.unwrap_or_else(|| cwd.clone()); if !init_root.exists() { std::fs::create_dir_all(&init_root).unwrap_or_else(|e| { @@ -218,7 +218,7 @@ async fn main() -> Result<(), std::io::Error> { } } else if let Some(explicit_root) = explicit_path { // An explicit path was given on the command line. - // Open it directly — scaffold .storkit/ if it is missing — and + // Open it directly — scaffold .huskies/ if it is missing — and // exit with a clear error message if the path is invalid. match io::fs::open_project( explicit_root.to_string_lossy().to_string(), @@ -240,7 +240,7 @@ async fn main() -> Result<(), std::io::Error> { } } } else { - // No path argument — auto-detect a .storkit/ project in cwd or + // No path argument — auto-detect a .huskies/ project in cwd or // parent directories (preserves existing behaviour). if let Some(project_root) = find_story_kit_root(&cwd) { io::fs::open_project( @@ -259,8 +259,8 @@ async fn main() -> Result<(), std::io::Error> { config::ProjectConfig::load(&project_root) .unwrap_or_else(|e| panic!("Invalid project.toml: {e}")); } else { - // No .storkit/ found in cwd or parents — scaffold cwd as a new - // project, exactly like `storkit .` does. + // No .huskies/ found in cwd or parents — scaffold cwd as a new + // project, exactly like `huskies .` does. io::fs::open_project( cwd.to_string_lossy().to_string(), &app_state, @@ -277,7 +277,7 @@ async fn main() -> Result<(), std::io::Error> { // Enable persistent server log file now that the project root is known. if let Some(ref root) = *app_state.project_root.lock().unwrap() { - let log_dir = root.join(".storkit").join("logs"); + let log_dir = root.join(".huskies").join("logs"); let _ = std::fs::create_dir_all(&log_dir); log_buffer::global().set_log_file(log_dir.join("server.log")); } @@ -294,7 +294,7 @@ async fn main() -> Result<(), std::io::Error> { let watchdog_root: Option = app_state.project_root.lock().unwrap().clone(); AgentPool::spawn_watchdog(Arc::clone(&agents), watchdog_root); if let Some(ref root) = *app_state.project_root.lock().unwrap() { - let work_dir = root.join(".storkit").join("work"); + let work_dir = root.join(".huskies").join("work"); if work_dir.is_dir() { let watcher_config = config::ProjectConfig::load(root) .map(|c| c.watcher) @@ -521,7 +521,7 @@ async fn main() -> Result<(), std::io::Error> { let app = build_routes(ctx, whatsapp_ctx.clone(), slack_ctx.clone(), port); // Optional Matrix bot: connect to the homeserver and start listening for - // messages if `.storkit/bot.toml` is present and enabled. + // messages if `.huskies/bot.toml` is present and enabled. if let Some(ref root) = startup_root { chat::transport::matrix::spawn_bot( root, @@ -574,13 +574,13 @@ async fn main() -> Result<(), std::io::Error> { startup_agents.auto_assign_available_work(&root).await; }); } - let host = std::env::var("STORKIT_HOST").unwrap_or_else(|_| "127.0.0.1".to_string()); + let host = std::env::var("HUSKIES_HOST").unwrap_or_else(|_| "127.0.0.1".to_string()); let addr = format!("{host}:{port}"); println!( "\x1b[95;1m ____ _ _ ___ _ \n / ___|| |_ ___ _ __| | _|_ _| |_ \n \\___ \\| __/ _ \\| '__| |/ /| || __|\n ___) | || (_) | | | < | || |_ \n |____/ \\__\\___/|_| |_|\\_\\___|\\__|\n\x1b[0m" ); - println!("STORKIT_PORT={port}"); + println!("HUSKIES_PORT={port}"); println!("\x1b[96;1mFrontend:\x1b[0m \x1b[94mhttp://{addr}\x1b[0m"); println!("\x1b[92;1mOpenAPI Docs:\x1b[0m \x1b[94mhttp://{addr}/docs\x1b[0m"); @@ -637,7 +637,7 @@ mod tests { #[should_panic(expected = "Invalid project.toml: Duplicate agent name")] fn panics_on_duplicate_agent_names() { let tmp = tempfile::tempdir().unwrap(); - let sk = tmp.path().join(".storkit"); + let sk = tmp.path().join(".huskies"); std::fs::create_dir_all(&sk).unwrap(); std::fs::write( sk.join("project.toml"), diff --git a/server/src/rebuild.rs b/server/src/rebuild.rs index 5139a801..9ab8074d 100644 --- a/server/src/rebuild.rs +++ b/server/src/rebuild.rs @@ -85,7 +85,7 @@ impl BotShutdownNotifier { /// Rebuild the server binary and re-exec. /// /// 1. Gracefully stops all running agents (kills PTY children). -/// 2. Runs `cargo build [-p storkit]` from the workspace root, matching +/// 2. Runs `cargo build [-p huskies]` from the workspace root, matching /// the current build profile (debug or release). /// 3. If the build fails, returns the build error (server stays up). /// 4. If the build succeeds, sends a best-effort shutdown notification (if a @@ -151,9 +151,9 @@ pub async fn rebuild_and_restart( // 4. Build the server binary, matching the current build profile so the // re-exec via current_exe() picks up the new binary. let build_args: Vec<&str> = if cfg!(debug_assertions) { - vec!["build", "-p", "storkit"] + vec!["build", "-p", "huskies"] } else { - vec!["build", "--release", "-p", "storkit"] + vec!["build", "--release", "-p", "huskies"] }; slog!("[rebuild] cargo {}", build_args.join(" ")); let output = tokio::task::spawn_blocking({ @@ -187,22 +187,22 @@ pub async fn rebuild_and_restart( // 6. Re-exec with the new binary. // Use the cargo output path rather than current_exe() so that rebuilds // inside Docker work correctly — the running binary may be installed at - // /usr/local/bin/storkit (read-only) while cargo writes the new binary - // to /app/target/release/storkit (a writable volume). + // /usr/local/bin/huskies (read-only) while cargo writes the new binary + // to /app/target/release/huskies (a writable volume). let new_exe = if cfg!(debug_assertions) { - workspace_root.join("target/debug/storkit") + workspace_root.join("target/debug/huskies") } else { - workspace_root.join("target/release/storkit") + workspace_root.join("target/release/huskies") }; let args: Vec = std::env::args().collect(); // Remove the port file before re-exec so the new process can write its own. - let port_file = project_root.join(".storkit_port"); + let port_file = project_root.join(".huskies_port"); if port_file.exists() { let _ = std::fs::remove_file(&port_file); } // Also check cwd for port file. - let cwd_port_file = std::path::Path::new(".storkit_port"); + let cwd_port_file = std::path::Path::new(".huskies_port"); if cwd_port_file.exists() { let _ = std::fs::remove_file(cwd_port_file); } diff --git a/server/src/store.rs b/server/src/store.rs index bf560e84..342499a7 100644 --- a/server/src/store.rs +++ b/server/src/store.rs @@ -144,13 +144,13 @@ mod tests { { let store = JsonFileStore::new(path.clone()).unwrap(); - store.set("name", json!("storkit")); + store.set("name", json!("huskies")); store.set("version", json!(1)); store.save().expect("save should succeed"); } let store = JsonFileStore::new(path).unwrap(); - assert_eq!(store.get("name"), Some(json!("storkit"))); + assert_eq!(store.get("name"), Some(json!("huskies"))); assert_eq!(store.get("version"), Some(json!(1))); } diff --git a/server/src/worktree.rs b/server/src/worktree.rs index 16ae5867..b878326e 100644 --- a/server/src/worktree.rs +++ b/server/src/worktree.rs @@ -7,7 +7,7 @@ use std::process::Command; /// at the given port. pub fn write_mcp_json(dir: &Path, port: u16) -> Result<(), String> { let content = format!( - "{{\n \"mcpServers\": {{\n \"storkit\": {{\n \"type\": \"http\",\n \"url\": \"http://localhost:{port}/mcp\"\n }}\n }}\n}}\n" + "{{\n \"mcpServers\": {{\n \"huskies\": {{\n \"type\": \"http\",\n \"url\": \"http://localhost:{port}/mcp\"\n }}\n }}\n}}\n" ); std::fs::write(dir.join(".mcp.json"), content).map_err(|e| format!("Write .mcp.json: {e}")) } @@ -25,10 +25,10 @@ pub struct WorktreeListEntry { pub path: PathBuf, } -/// Worktree path inside the project: `{project_root}/.storkit/worktrees/{story_id}`. +/// Worktree path inside the project: `{project_root}/.huskies/worktrees/{story_id}`. pub fn worktree_path(project_root: &Path, story_id: &str) -> PathBuf { project_root - .join(".storkit") + .join(".huskies") .join("worktrees") .join(story_id) } @@ -56,7 +56,7 @@ fn detect_base_branch(project_root: &Path) -> String { /// Create a git worktree for the given story. /// -/// - Creates the worktree at `{project_root}/.storkit/worktrees/{story_id}` +/// - Creates the worktree at `{project_root}/.huskies/worktrees/{story_id}` /// on branch `feature/story-{story_id}`. /// - Writes `.mcp.json` in the worktree pointing to the MCP server at `port`. /// - Runs setup commands from the config for each component. @@ -142,14 +142,14 @@ fn create_worktree_sync(project_root: &Path, wt_path: &Path, branch: &str) -> Re } // Enable sparse checkout to exclude pipeline files from the worktree. - // This prevents .storkit/work/ changes from ending up in feature branches, + // This prevents .huskies/work/ changes from ending up in feature branches, // which cause rename/delete merge conflicts when merging back to master. configure_sparse_checkout(wt_path)?; Ok(()) } -/// Placeholder for worktree isolation of `.storkit/work/`. +/// Placeholder for worktree isolation of `.huskies/work/`. /// /// Previous approaches (sparse checkout, skip-worktree) all leaked state /// from worktrees back to the main checkout's config/index. For now this @@ -214,11 +214,11 @@ pub async fn remove_worktree_by_story_id( remove_worktree(project_root, &info, config).await } -/// List all worktrees under `{project_root}/.storkit/worktrees/`. +/// List all worktrees under `{project_root}/.huskies/worktrees/`. /// Find the worktree path for a given story ID, if it exists. pub fn find_worktree_path(project_root: &Path, story_id: &str) -> Option { let wt_path = project_root - .join(".storkit") + .join(".huskies") .join("worktrees") .join(story_id); if wt_path.is_dir() { @@ -229,7 +229,7 @@ pub fn find_worktree_path(project_root: &Path, story_id: &str) -> Option Result, String> { - let worktrees_dir = project_root.join(".storkit").join("worktrees"); + let worktrees_dir = project_root.join(".huskies").join("worktrees"); if !worktrees_dir.exists() { return Ok(Vec::new()); } @@ -376,7 +376,7 @@ mod tests { let path = worktree_path(project_root, "42_my_story"); assert_eq!( path, - Path::new("/home/user/my-project/.storkit/worktrees/42_my_story") + Path::new("/home/user/my-project/.huskies/worktrees/42_my_story") ); } @@ -390,7 +390,7 @@ mod tests { #[test] fn list_worktrees_returns_subdirs() { let tmp = TempDir::new().unwrap(); - let worktrees_dir = tmp.path().join(".storkit").join("worktrees"); + let worktrees_dir = tmp.path().join(".huskies").join("worktrees"); fs::create_dir_all(worktrees_dir.join("42_story_a")).unwrap(); fs::create_dir_all(worktrees_dir.join("43_story_b")).unwrap(); // A file (not dir) — should be ignored @@ -439,8 +439,8 @@ mod tests { fs::create_dir_all(&project_root).unwrap(); init_git_repo(&project_root); - // Create a tracked file under .storkit/work/ on the initial branch - let work_dir = project_root.join(".storkit").join("work"); + // Create a tracked file under .huskies/work/ on the initial branch + let work_dir = project_root.join(".huskies").join("work"); fs::create_dir_all(&work_dir).unwrap(); fs::write(work_dir.join("test_story.md"), "# Test").unwrap(); Command::new("git") @@ -458,14 +458,14 @@ mod tests { let branch = "feature/test-sparse"; create_worktree_sync(&project_root, &wt_path, branch).unwrap(); - // Worktree should have all files including .storkit/work/ - assert!(wt_path.join(".storkit").join("work").exists()); + // Worktree should have all files including .huskies/work/ + assert!(wt_path.join(".huskies").join("work").exists()); assert!(wt_path.join(".git").exists()); // Main checkout must NOT be affected by worktree creation. assert!( work_dir.exists(), - ".storkit/work/ must still exist in the main checkout" + ".huskies/work/ must still exist in the main checkout" ); } @@ -679,7 +679,7 @@ mod tests { // Create a directory that looks like a worktree but isn't registered with git let wt_path = project_root - .join(".storkit") + .join(".huskies") .join("worktrees") .join("orphan"); fs::create_dir_all(&wt_path).unwrap(); @@ -700,7 +700,7 @@ mod tests { init_git_repo(&project_root); let wt_path = project_root - .join(".storkit") + .join(".huskies") .join("worktrees") .join("test_rm"); create_worktree_sync(&project_root, &wt_path, "feature/test-rm").unwrap(); diff --git a/website/index.html b/website/index.html index 40ef18e2..55bb808c 100644 --- a/website/index.html +++ b/website/index.html @@ -3,8 +3,8 @@ - Storkit — Story-Driven Development for AI Agents - + Huskies — Story-Driven Development for AI Agents + @@ -17,8 +17,8 @@
-

What is Storkit?

-

Storkit is an autonomous development pipeline that turns user stories into tested, shipped code. You describe what you want. AI agents handle the rest — implementation, testing, code review, and merge.

+

What is Huskies?

+

Huskies is an autonomous development pipeline that turns user stories into tested, shipped code. You describe what you want. AI agents handle the rest — implementation, testing, code review, and merge.

Talk to it from your IDE, a chat room, or WhatsApp. Stories flow through a structured pipeline: backlog, current, QA, merge, done.

@@ -57,7 +57,7 @@

Get in touch

-

Storkit is built by Crashlabs. Interested in early access or have questions? Reach out at hello@storkit.dev.

+

Huskies is built by Crashlabs. Interested in early access or have questions? Reach out at hello@huskies.dev.