huskies: merge 585_bug_bot_not_aware_of_actual_running_port_defaults_to_3001

This commit is contained in:
dave
2026-04-15 23:42:46 +00:00
parent 2663c5f91f
commit 4a1c6b4cfa
3 changed files with 26 additions and 15 deletions
+3 -2
View File
@@ -349,13 +349,14 @@ pub(super) fn tool_dump_crdt(args: &Value) -> Result<String, String> {
.map_err(|e| format!("Serialization error: {e}")) .map_err(|e| format!("Serialization error: {e}"))
} }
/// MCP tool: return the server version and build hash. /// MCP tool: return the server version, build hash, and running port.
pub(super) fn tool_get_version() -> Result<String, String> { pub(super) fn tool_get_version(ctx: &AppContext) -> Result<String, String> {
let build_hash = let build_hash =
std::fs::read_to_string(".huskies/build_hash").unwrap_or_else(|_| "unknown".to_string()); std::fs::read_to_string(".huskies/build_hash").unwrap_or_else(|_| "unknown".to_string());
serde_json::to_string_pretty(&json!({ serde_json::to_string_pretty(&json!({
"version": env!("CARGO_PKG_VERSION"), "version": env!("CARGO_PKG_VERSION"),
"build_hash": build_hash.trim(), "build_hash": build_hash.trim(),
"port": ctx.agents.port(),
})) }))
.map_err(|e| format!("Serialization error: {e}")) .map_err(|e| format!("Serialization error: {e}"))
} }
+2 -2
View File
@@ -897,7 +897,7 @@ fn handle_tools_list(id: Option<Value>) -> JsonRpcResponse {
}, },
{ {
"name": "get_version", "name": "get_version",
"description": "Return the server version and build hash.", "description": "Return the server version, build hash, and running port.",
"inputSchema": { "inputSchema": {
"type": "object", "type": "object",
"properties": {} "properties": {}
@@ -1330,7 +1330,7 @@ async fn handle_tools_call(id: Option<Value>, params: &Value, ctx: &AppContext)
"get_pipeline_status" => story_tools::tool_get_pipeline_status(ctx), "get_pipeline_status" => story_tools::tool_get_pipeline_status(ctx),
// Diagnostics // Diagnostics
"get_server_logs" => diagnostics::tool_get_server_logs(&args), "get_server_logs" => diagnostics::tool_get_server_logs(&args),
"get_version" => diagnostics::tool_get_version(), "get_version" => diagnostics::tool_get_version(ctx),
// Server lifecycle // Server lifecycle
"rebuild_and_restart" => diagnostics::tool_rebuild_and_restart(ctx).await, "rebuild_and_restart" => diagnostics::tool_rebuild_and_restart(ctx).await,
// Permission bridge (Claude Code → frontend dialog) // Permission bridge (Claude Code → frontend dialog)
+21 -11
View File
@@ -37,6 +37,13 @@ pub(crate) async fn ensure_project_root_with_story_kit(
if !path.join(".huskies").is_dir() { if !path.join(".huskies").is_dir() {
scaffold_story_kit(&path, port)?; scaffold_story_kit(&path, port)?;
} }
// Always update .mcp.json with the current port so the bot connects to
// the right endpoint even when HUSKIES_PORT changes between restarts.
let mcp_content = format!(
"{{\n \"mcpServers\": {{\n \"huskies\": {{\n \"type\": \"http\",\n \"url\": \"http://localhost:{port}/mcp\"\n }}\n }}\n}}\n"
);
fs::write(path.join(".mcp.json"), mcp_content)
.map_err(|e| format!("Failed to write .mcp.json: {}", e))?;
Ok(()) Ok(())
}) })
.await .await
@@ -194,16 +201,15 @@ mod tests {
} }
#[tokio::test] #[tokio::test]
async fn open_project_does_not_overwrite_existing_mcp_json() { async fn open_project_updates_mcp_json_with_current_port() {
// scaffold must NOT overwrite .mcp.json when it already exists — QA // .mcp.json must always be updated with the actual running port so the
// test servers share the real project root, and re-writing would // bot connects to the right MCP endpoint even when HUSKIES_PORT changes.
// clobber the file with the wrong port.
let dir = tempdir().unwrap(); let dir = tempdir().unwrap();
let project_dir = dir.path().join("myproject"); let project_dir = dir.path().join("myproject");
fs::create_dir_all(&project_dir).unwrap(); fs::create_dir_all(&project_dir).unwrap();
// Pre-write .mcp.json with a different port to simulate an already-configured project. // Pre-write .mcp.json with a different port to simulate a stale file.
let mcp_path = project_dir.join(".mcp.json"); let mcp_path = project_dir.join(".mcp.json");
fs::write(&mcp_path, "{\"existing\": true}").unwrap(); fs::write(&mcp_path, "{\"stale\": true}").unwrap();
let store = make_store(&dir); let store = make_store(&dir);
let state = SessionState::default(); let state = SessionState::default();
@@ -211,15 +217,19 @@ mod tests {
project_dir.to_string_lossy().to_string(), project_dir.to_string_lossy().to_string(),
&state, &state,
&store, &store,
3001, 3002,
) )
.await .await
.unwrap(); .unwrap();
assert_eq!( let content = fs::read_to_string(&mcp_path).unwrap();
fs::read_to_string(&mcp_path).unwrap(), assert!(
"{\"existing\": true}", content.contains("3002"),
"open_project must not overwrite an existing .mcp.json" "open_project must update .mcp.json with the actual running port"
);
assert!(
content.contains("localhost"),
"mcp.json must reference localhost"
); );
} }